整数翻转

10 篇文章 0 订阅

前几天在写道进制翻转的题目,发现JAVA提供了直接调用的方法

Integer.reverse(int i):二进制按位反转
很好奇点进去发现,源码如下:

/**
 * Returns the value obtained by reversing the order of the bits in the
 * two's complement binary representation of the specified {@code int}
 * value.
 *
 * @param i the value to be reversed
 * @return the value obtained by reversing order of the bits in the
 *     specified {@code int} value.
 * @since 1.5
 */
public static int reverse(int i) {
    // HD, Figure 7-1
    i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
    i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
    i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
    i = (i << 24) | ((i & 0xff00) << 8) |
        ((i >>> 8) & 0xff00) | (i >>> 24);
    return i;
}

这是什么神仙代码?一眼看过去丈二和尚摸不着头脑。

仔细推敲后发现:

不妨设 i i i的二进制如下:

1234567891011121314151617181920212223242526272829303132
b 1 b_{1} b1 b 2 b_{2} b2 b 3 b_{3} b3 b 4 b_{4} b4 b 5 b_{5} b5 b 6 b_{6} b6 b 7 b_{7} b7 b 8 b_{8} b8 b 9 b_{9} b9 b 10 b_{10} b10 b 11 b_{11} b11 b 12 b_{12} b12 b 13 b_{13} b13 b 14 b_{14} b14 b 15 b_{15} b15 b 16 b_{16} b16 b 17 b_{17} b17 b 18 b_{18} b18 b 19 b_{19} b19 b 20 b_{20} b20 b 21 b_{21} b21 b 22 b_{22} b22 b 23 b_{23} b23 b 24 b_{24} b24 b 25 b_{25} b25 b 26 b_{26} b26 b 27 b_{27} b27 b 28 b_{28} b28 b 29 b_{29} b29 b 30 b_{30} b30 b 31 b_{31} b31 b 32 b_{32} b32

0x55555555二进制:0101 0101 0101 0101 0101 0101 0101 0101

所以很容易发现:

(i & 0x55555555) << 1的结果是:取出 i i i的偶数位(左移末尾补0),结果如下:记为 i 1 i_1 i1

1234567891011121314151617181920212223242526272829303132
b 2 b_{2} b20 b 4 b_{4} b40 b 6 b_{6} b60 b 8 b_{8} b80 b 10 b_{10} b100 b 12 b_{12} b120 b 14 b_{14} b140 b 16 b_{16} b160 b 18 b_{18} b180 b 20 b_{20} b200 b 22 b_{22} b220 b 24 b_{24} b240 b 26 b_{26} b260 b 28 b_{28} b280 b 30 b_{30} b300 b 32 b_{32} b320

(i >>> 1) & 0x55555555的结果是:取出 i i i的奇数为(无符号左移首位补0),结果如下:记为 i 2 i_2 i2

1234567891011121314151617181920212223242526272829303132
0 b 1 b_{1} b10 b 3 b_{3} b30 b 5 b_{5} b50 b 7 b_{7} b70 b 9 b_{9} b90 b 11 b_{11} b110 b 13 b_{13} b130 b 15 b_{15} b150 b 17 b_{17} b170 b 19 b_{19} b190 b 21 b_{21} b210 b 23 b_{23} b230 b 25 b_{25} b250 b 27 b_{27} b270 b 29 b_{29} b290 b 31 b_{31} b31

再将 i 1 i_1 i1、记为 i 2 i_2 i2按位取运算,结果如下:

1234567891011121314151617181920212223242526272829303132
b 2 b_{2} b2 b 1 b_{1} b1 b 4 b_{4} b4 b 3 b_{3} b3 b 6 b_{6} b6 b 5 b_{5} b5 b 8 b_{8} b8 b 7 b_{7} b7 b 10 b_{10} b10 b 9 b_{9} b9 b 12 b_{12} b12 b 11 b_{11} b11 b 14 b_{14} b14 b 13 b_{13} b13 b 16 b_{16} b16 b 15 b_{15} b15 b 18 b_{18} b18 b 17 b_{17} b17 b 20 b_{20} b20 b 19 b_{19} b19 b 22 b_{22} b22 b 21 b_{21} b21 b 24 b_{24} b24 b 23 b_{23} b23 b 26 b_{26} b26 b 25 b_{25} b25 b 28 b_{28} b28 b 27 b_{27} b27 b 30 b_{30} b30 b 29 b_{29} b29 b 32 b_{32} b32 b 31 b_{31} b31

可以看出i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;的作用便是将 i i i中的每两个相邻位交换位置

同理:

0x33333333二进制:0011 0011 0011 0011 0011 0011 0011 0011

所以应当是每四位中的相邻两位交换,结果如下:

1234567891011121314151617181920212223242526272829303132
b 4 b_{4} b4 b 3 b_{3} b3 b 2 b_{2} b2 b 1 b_{1} b1 b 8 b_{8} b8 b 7 b_{7} b7 b 6 b_{6} b6 b 5 b_{5} b5 b 12 b_{12} b12 b 11 b_{11} b11 b 10 b_{10} b10 b 9 b_{9} b9 b 16 b_{16} b16 b 15 b_{15} b15 b 14 b_{14} b14 b 13 b_{13} b13 b 20 b_{20} b20 b 19 b_{19} b19 b 18 b_{18} b18 b 17 b_{17} b17 b 24 b_{24} b24 b 23 b_{23} b23 b 22 b_{22} b22 b 21 b_{21} b21 b 28 b_{28} b28 b 27 b_{27} b27 b 26 b_{26} b26 b 25 b_{25} b25 b 32 b_{32} b32 b 31 b_{31} b31 b 30 b_{30} b30 b 29 b_{29} b29

0x0f0f0f0f二进制:0000 1111 0000 1111 0000 1111 0000 1111

所以应当是每 八位中的相邻四位交换,结果如下:

1234567891011121314151617181920212223242526272829303132
b 8 b_{8} b8 b 7 b_{7} b7 b 6 b_{6} b6 b 5 b_{5} b5 b 4 b_{4} b4 b 3 b_{3} b3 b 2 b_{2} b2 b 1 b_{1} b1 b 16 b_{16} b16 b 15 b_{15} b15 b 14 b_{14} b14 b 13 b_{13} b13 b 12 b_{12} b12 b 11 b_{11} b11 b 10 b_{10} b10 b 9 b_{9} b9 b 24 b_{24} b24 b 23 b_{23} b23 b 22 b_{22} b22 b 21 b_{21} b21 b 20 b_{20} b20 b 19 b_{19} b19 b 18 b_{18} b18 b 17 b_{17} b17 b 32 b_{32} b32 b 31 b_{31} b31 b 30 b_{30} b30 b 29 b_{29} b29 b 28 b_{28} b28 b 27 b_{27} b27 b 26 b_{26} b26 b 25 b_{25} b25

到最后一步:

i = (i << 24) | ((i & 0xff00) << 8) | ((i >>> 8) & 0xff00) | (i >>> 24);

注意:0xff00实际上是0x0000ff00

(i << 24)结果:

1234567891011121314151617181920212223242526272829303132
b 32 b_{32} b32 b 31 b_{31} b31 b 30 b_{30} b30 b 29 b_{29} b29 b 28 b_{28} b28 b 27 b_{27} b27 b 26 b_{26} b26 b 25 b_{25} b25000000000000000000000000

(i & 0xff00) << 8 结果:

1234567891011121314151617181920212223242526272829303132
00000000 b 24 b_{24} b24 b 23 b_{23} b23 b 22 b_{22} b22 b 21 b_{21} b21 b 20 b_{20} b20 b 19 b_{19} b19 b 18 b_{18} b18 b 17 b_{17} b170000000000000000

(i >>> 8) & 0xff00 结果:

1234567891011121314151617181920212223242526272829303132
0000000000000000 b 16 b_{16} b16 b 15 b_{15} b15 b 14 b_{14} b14 b 13 b_{13} b13 b 12 b_{12} b12 b 11 b_{11} b11 b 10 b_{10} b10 b 9 b_{9} b900000000

(i >>> 24)结果:

1234567891011121314151617181920212223242526272829303132
000000000000000000000000 b 8 b_{8} b8 b 7 b_{7} b7 b 6 b_{6} b6 b 5 b_{5} b5 b 4 b_{4} b4 b 3 b_{3} b3 b 2 b_{2} b2 b 1 b_{1} b1

然后在取或运算,得到最后的翻转结果:

1234567891011121314151617181920212223242526272829303132
b 32 b_{32} b32 b 31 b_{31} b31 b 30 b_{30} b30 b 29 b_{29} b29 b 28 b_{28} b28 b 27 b_{27} b27 b 26 b_{26} b26 b 25 b_{25} b25 b 24 b_{24} b24 b 23 b_{23} b23 b 22 b_{22} b22 b 21 b_{21} b21 b 20 b_{20} b20 b 19 b_{19} b19 b 18 b_{18} b18 b 17 b_{17} b17 b 16 b_{16} b16 b 15 b_{15} b15 b 14 b_{14} b14 b 13 b_{13} b13 b 12 b_{12} b12 b 11 b_{11} b11 b 10 b_{10} b10 b 9 b_{9} b9 b 8 b_{8} b8 b 7 b_{7} b7 b 6 b_{6} b6 b 5 b_{5} b5 b 4 b_{4} b4 b 3 b_{3} b3 b 2 b_{2} b2 b 1 b_{1} b1

太神奇了!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值