比较两个数a、b的大小,不能使用大于/小于、if、switch,?:等判断语句
2016-06-08 11:45
483 查看
本文摘自:http://tangyuan1314.iteye.com/blog/1485559
今天面试碰到了这个问题,知道是位操作,不过当时没想起来,回来查了查总结一下。其实方法很简单,就是相减后看符号位,将减的结果的符号位移位到末尾,再和1与操作,或者直接和0x80000000与,得出的符号位再右移至末尾,作为数组的下标。int型占4字节,即32位,在-1为补码的机器上,1代表负数,0代表正数
C代码
<span style="white-space: normal; background-color: #ffffff;">int max(int x,int y)</span>
{
int buf[2]={x,y};
unsigned int z;
z=x-y;
z=z>>31;//符号位移至末尾,作为数组下标
return buf[z];
}
上述代码是从网上查的,这是基础版本,但是未考虑内存溢出,如127-(-128)得出的结果超出了8位所能表示的数。并且上述版本不可直接用java写,java中没有无符号类型,因为java中右移运算补位是根据符号位,符号位为1就补1,符号位为0就补0,因此右移后可和1与操作。
下面的版本是考虑溢出,即判断两个数的符号相同否,相同的话就不会产生溢出。不相同的话,直接看符号位就ok了。下面上代码。
C代码
int max1(int x,int y){//符号相同,返回x,y中的大值
unsigned int z;
z=((x-y)>>31)&1;
return (1-z)*x+z*y;//这种写法很巧妙
}
int max2(int x,int y){//符号不同,直接判断x的正负即可,返回最大值
unsigned int z;
z=(x>>31)&1;
return (1-z)*x+z*y;
}
int max(int x,int y){
unsigned int z;
z=((x^y)>>31)&1;//异或操作,判断符号位是否相同
return (1-z)*max1(x,y)+z*max2(x,y);
}
在考虑溢出的情况下,unsigned int z=((x^y)>;>;31)&1的值有两种可能,x、y同号时为0,x、y异号时为1。当x、y同号时x-y不会溢出,可参考max1,得出最大值;当x、y异号时,取正的那个就是最大值max。
其实上述的巧妙部分是基于插值,有人给出了精简的程序,思想同上。int max (int a, int b)
C代码
{
int g, r1, r2;
g = ((a^b) >;>; 31) & 1;
r1 = (a >;>; 31) & 1;
r2 = ((a-b) >;>; 31) & 1;
return g*(r1*b + (1-r1)*a) + (1-g)*(r2*b + (1-r2)*a);
}
总结一下:
1、基本思想:位操作,找符号位
a^b 的最高位 ---- 判断符号是否相同
a-b 的最高位 ---- 在符号相同的情况下判断大小
a 的最高位 ---- a的符号
b 的最高位 ---- b的符号
2、得出大(小)的数
把大小关系对应到一个数组当中
使用插值
补充:
以上max1、max2和max的代码中可以优化成无需乘法运算,下面以max1为例进行优化说明:
int max1(int x,int y){//符号相同,返回x,y中的大值
unsigned int z;
z=(x-y)>>31; //注意:负数右移,高位补1;正数右移,高位补0
return (~z & x) + (z & y);
}
今天面试碰到了这个问题,知道是位操作,不过当时没想起来,回来查了查总结一下。其实方法很简单,就是相减后看符号位,将减的结果的符号位移位到末尾,再和1与操作,或者直接和0x80000000与,得出的符号位再右移至末尾,作为数组的下标。int型占4字节,即32位,在-1为补码的机器上,1代表负数,0代表正数
C代码
<span style="white-space: normal; background-color: #ffffff;">int max(int x,int y)</span>
{
int buf[2]={x,y};
unsigned int z;
z=x-y;
z=z>>31;//符号位移至末尾,作为数组下标
return buf[z];
}
上述代码是从网上查的,这是基础版本,但是未考虑内存溢出,如127-(-128)得出的结果超出了8位所能表示的数。并且上述版本不可直接用java写,java中没有无符号类型,因为java中右移运算补位是根据符号位,符号位为1就补1,符号位为0就补0,因此右移后可和1与操作。
下面的版本是考虑溢出,即判断两个数的符号相同否,相同的话就不会产生溢出。不相同的话,直接看符号位就ok了。下面上代码。
C代码
int max1(int x,int y){//符号相同,返回x,y中的大值
unsigned int z;
z=((x-y)>>31)&1;
return (1-z)*x+z*y;//这种写法很巧妙
}
int max2(int x,int y){//符号不同,直接判断x的正负即可,返回最大值
unsigned int z;
z=(x>>31)&1;
return (1-z)*x+z*y;
}
int max(int x,int y){
unsigned int z;
z=((x^y)>>31)&1;//异或操作,判断符号位是否相同
return (1-z)*max1(x,y)+z*max2(x,y);
}
在考虑溢出的情况下,unsigned int z=((x^y)>;>;31)&1的值有两种可能,x、y同号时为0,x、y异号时为1。当x、y同号时x-y不会溢出,可参考max1,得出最大值;当x、y异号时,取正的那个就是最大值max。
其实上述的巧妙部分是基于插值,有人给出了精简的程序,思想同上。int max (int a, int b)
C代码
{
int g, r1, r2;
g = ((a^b) >;>; 31) & 1;
r1 = (a >;>; 31) & 1;
r2 = ((a-b) >;>; 31) & 1;
return g*(r1*b + (1-r1)*a) + (1-g)*(r2*b + (1-r2)*a);
}
总结一下:
1、基本思想:位操作,找符号位
a^b 的最高位 ---- 判断符号是否相同
a-b 的最高位 ---- 在符号相同的情况下判断大小
a 的最高位 ---- a的符号
b 的最高位 ---- b的符号
2、得出大(小)的数
把大小关系对应到一个数组当中
使用插值
补充:
以上max1、max2和max的代码中可以优化成无需乘法运算,下面以max1为例进行优化说明:
int max1(int x,int y){//符号相同,返回x,y中的大值
unsigned int z;
z=(x-y)>>31; //注意:负数右移,高位补1;正数右移,高位补0
return (~z & x) + (z & y);
}
相关文章推荐
- 步进电机 28BYJ-48介绍和驱动及编程
- quartz学习
- calltree查看工程代码中的函数调用关系
- 基于.Net Framework 4.0 Web API开发(5):ASP.NET Web APIs AJAX 跨域请求解决办法(CORS实现)
- iOS_界面流畅的细节
- android5.0 audioflinger
- Android之缓存网络图片
- JavaScript 高级课程之缓冲/多个DIV运动框架
- Mac 下解压NDK .bin文件
- [sed]直接修改文件
- WebServices简介 SOAP\WSDL
- 深入浅出聊Unity3D优化:从Draw Calls到GC
- zookeeper适用场景:zookeeper解决了哪些问题
- POJ-2398 Toy Storage
- 作业九 ——报告及总结(6.16更新)
- linux 软链接 硬链接
- NIO 入门
- ImageLoader-----适配器
- ffmpeg - 几个实用的命令
- mesos-dns & marathon-lb