看到几个有意思的按位操作的写法。
1.大概改动了下为了方便理解,参数是int型且大于等于65536,返回这个int型的十位和个位。
public static int getTenAndOne(int value){ if (value < 0) { throw new RuntimeException("不管负数了"); } int q = value / 100; int result = value - ((q << 6) + (q << 5) + (q << 2)); return result; }通常我们计算一个数的后两位时,都是用 int result = value%100,但这里不是这样玩的。我记得看过一本书讲JAVA在%运算符的时候,实际是int result = value-value/100*100。看看上面那个方法里其实跟这个很像。这么看来
((q << 6) + (q << 5) + (q << 2))
这个操作其实就是 (a/100)*100的操作,可是移位是怎么变成*100的呢,曾经的基础书中这么讲过,向左移移动一位表示*2,所以对上面的表达式进行整理就是 q*2^6+q*2^5+q*2^2=q*(2^6+2^5+2^2)=q*100。呃……。其实当我想明白这个的时候,又一次感叹,无处不在的数学啊。
2.这个是计算出一个小于65536的整数的,个位数是多少。
pulic static int getOne(int value){ if(value<0||value>=65536){ throw new RuntimeException("就是不管负数和超限的数"); } int q = (value * 52429) >>> 19; int result = value - ((q << 3) + (q << 1)); return result;}根据例1里面的经验,可以很容易看出,其实这个例子就是result=value-value/10*10;
特别是
int result = value - ((q << 3) + (q << 1));
非常好理解就是 value-(q*2^3+q*^2)=value-q*(8+2)=value-q*10 ,那么上面那句话其实就是value/10的意思了,可是简单的value/10,怎会冒出来乘以52429然后再无符号右移19位呢。我google出来的解释,也算学习了一下。
(i * 52429) >> 19 = i / 10 原理: 52429 / 2 ^19 = 0.10000038146972656 所以(i * 52429) >> 19 = i * 0.1 注意: 2^10=1024, 103/1024=0.1005859375 2^11=2048, 205/2048=0.10009765625 2^12=4096, 410/4096=0.10009765625 2^13=8192, 820/8192=0.10009765625 2^14=16384, 1639/16384=0.10003662109375 2^15=32768, 3277/32768=0.100006103515625 2^16=65536, 6554/65536=0.100006103515625 2^17=131072, 13108/131072=0.100006103515625 2^18=262144, 26215/262144=0.10000228881835938 2^19=524288, 52429/524288=0.10000038146972656 精度19最高,超过20 * i 就溢出了 然后: (i + (i << 2) + (i << 3) + (i << 6) + (i << 7) + (i << 10) + (i << 11) + (i<<14) + (i<<15)) >> 19 = i / 10
以上两个例子是在jedis代码中看到的,同时在JDK里的Integer类中的 static void getChars(int i, int index, char[] buf)里也有。看来jedis作者对JDK源码有认真阅读啊。
3.求一个离一个正整数向上最近的2的次方。
public static int nextPowerOfTwo (int value) { if (value == 0) { return 1; } value--; value |= value >> 1; value |= value >> 2; value |= value >> 4; value |= value >> 8; value |= value >> 16; return value + 1;}其实求一个整数向上最近的2的次方就是这个整数左数第一个1以下所有位全部变为1再加1
比如232用二进制表示就是
00000000000000000000000011101000 它的向上最近二进制数就是00000000000000000000000011111111+1
依据上面的理论,这个代码其实就是再逐步的把这个数都变成1,然后再+1
还是以232为例子,就不写成4个字节的形式了
232 = 11101000
1)
1110 1000>>1 //等于0111 0100 就肯定把最高1位的下一位变成了1 1110 1000 | 0111 0100 //等于 1111 1100 就把最高两位就变成1了2)
1111 1100>>2 //等于0011 1111 就等于把标红两位变成1 1111 1100 | 0011 1111 //等于 1111 1111 相当于把最高四位变成13)
1111 1111 >>4 //等于 0000 1111 就等于把标红四位变成1 1111 1111 | 0000 1111 //等于 1111 1111 相当于把最高位的1个字节变成1
4)其实就把最高的两个字节变成1
5)把整个int四个字节全部变成1
如上过程,整个int型数的最高的1位以下全部变成了1,最后再加上1 就完成了整个技巧,并返回结果。