我们知道在我们对一个数进行位运算的时候,是在这个数的补码上进行的,对于补码我们知道,正数的补码是原码,负数的补码为原码除了最高位的符号位,取反,然后加1。把补码转换成原码的时候,正数还是原码,负数时把补码除了符号位取反然后加1(我们可以发现如果这时候连符号位也求反,然后加1,与以前不同的只是少了一个符号位,现在实际上就是这个数的绝对值)。所以我们可以得到对一个负数求绝对值的表达式为
- int SignReversal(int a)
- {
- return ~a + 1;
- }
那么由这些知识我们可以很快地得到求一个数的绝对值的表达式:
先移位来取符号位,int i = a >> 31;要注意如果a为正数,i等于0,为负数,i等于-1。然后对i进行判断——如果i等于0,直接返回。否之,返回~a+1。完整代码如下:
- //by MoreWindows( http://blog.csdn.net/MoreWindows )
- int my_abs(int a)
- {
- int i = a >> 31;
- return i == 0 ? a : (~a + 1);
- }
现在再分析下。对于任何数,与0异或都会保持不变,与-1即0xFFFFFFFF异或就相当于取反。因此,a与i异或后再减i(因为i为0或-1,所以减i即是要么加0要么加1)也可以得到绝对值。所以可以对上面代码优化下:
- //by MoreWindows( http://blog.csdn.net/MoreWindows )
- int my_abs(int a)
- {
- int i = a >> 31;
- return ((a ^ i) - i);
- }
而且有些笔面试题就要求这样做(比如不让用if语句的时候),因此建议读者记住该方法