java求绝对值absultevalue,位运算常见技巧

在新浪微博上看到一篇文章写位运算的写的很深入,文章链接见末尾,特此mark。

0.位运算的种类

符号

名称

运算规则

&

两个位都为1时,结果才为1,否则都为0

l

两个位都是0时,结果才为1,否则都为0

^

异或

两个位都相同为0,否则为1

~

取反

0->1,1->0

<<

左移

各二进位全部左移若干位,高位丢弃,低位补0

>>

右移

各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

markdown中|我不知道怎么表示,就用l了

1.判断两个整数是否符号相反

bool oppositeSigns(int x, int y)

{

bool f = ((x ^ y) < 0); // true iff x and y have opposite signs

return f;

}

2.判断一个数的符号

bool isUnSignInt(int v){

int sign; // the result goes here

// CHAR_BIT is the number of bits per byte (normally 8).

sign = -(v < 0); // if v < 0 then -1, else 0.

// or, to avoid branching on CPUs with flag registers (IA32):

sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT – 1));

// or, for one less instruction (but not portable):

sign = v >> (sizeof(int) * CHAR_BIT – 1);

return sign == 1;

}

3.求一个数的绝对值

int absulteValue(int v){

unsigned int r; // the result goes here

int const mask = v >> (sizeof(int) * CHAR_BIT – 1);

/*explain:在计算机中,负数以其正值的补码形式表达。

什么叫补码呢?这得从原码,反码说起。

原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。

比如 00000000 00000000 00000000 00000101 是 5的 原码。

反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码。

取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)

比如:将00000000 00000000 00000000 00000101每一位取反,得11111111 11111111 11111111 11111010。

称:11111111 11111111 11111111 11111010 是 00000000 00000000 00000000 00000101 的反码。

反码是相互的,所以也可称:

11111111 11111111 11111111 11111010 和 00000000 00000000 00000000 00000101 互为反码。

补码:反码加1称为补码。

也就是说,要得到一个数的补码,先得到反码,然后将反码加上1,所得数称为补码。

比如:00000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。

那么,补码为:

11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011

所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。

所以获取一个负数的绝对就是将负数取反在+1即可

所以最初的形式可写成

int my_abs(int a)

{

int i = a >> 31;

return i == 0 ? a : (~a + 1);

}

现在再分析下。对于任何数,与0异或都会保持不变(异或是两个位相同为0,相异位1),与-1即0xFFFFFFFF异或就相当于取反。

因此,v与mask异或后再减mask(因为mask为0或-1,所以减mask即是要么加0要么加1)也可以得到绝对值。所以可以对上面代码优化下:

r = (v ^ mask) – mask;

*/

r = (v + mask) ^ mask;

//or

//r = (v ^ mask) – mask;

return r;

}

4.计算最大最小值

int max(int x, int y){

/*

*利用一点,对于任何数a,因为0的二进制全为0,有a&0 = 0,因为-1的二进制全为1,有a&(-1) = a

如果x>y,x

如果x

于是能求得较大值。较小值类似。

If you know that INT_MIN <= x – y <= INT_MAX, then you can use the following, which are faster because (x – y) only needs to be evaluated once.

r = y + ((x – y) & ((x – y) >> (sizeof(int) * CHAR_BIT – 1))); // min(x, y)

r = x – ((x – y) & ((x – y) >> (sizeof(int) * CHAR_BIT – 1))); // max(x, y)

*/

return x ^ ((x ^ y) & -(x < y));

}

5.计算一个值是否是2的次幂

bool isPowerOfTwo(int x){

//如果一个数是2的次幂,那么除首位,其余为肯定都为0,减一后其余为为1

bool f = x && !(x & (x – 1));

return f;

}

6.交换

void swap(int &x, int &y){

/*异或运算有两个特性:

1、一个数异或本身恒等于0,如5^5恒等于0;

2、一个数异或0恒等于本身,如5^0恒等于5。*/

if (x != y)

{

x ^= y;

y ^= x;

x ^= y;

}

}

后面的内容没那个太深,暂时用到的可能性不太,如果后期有业余精力再去深入研究。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平