位运算
二进制的最低位, 即最右边的位.
二进制的最高位, 即最左边的位.
采用原码表示时, 二进制的最高位是符号位, 0表示正数, 1表示负数.
原码的缺点是符号位不能参与运算, 每个有符号数在计算时都需要区分符号位再计算.
原码表示时, 0有两种表示方式.
可以表示为
可以表示为
00000000 (+0), 也可以表示为 10000000 (-0).从原码发展而来.
采用反码表示时,
正数的情况下与原码相同,
负数的情况下为原码符号位以外的所有位取反.
正数的情况下与原码相同,
负数的情况下为原码符号位以外的所有位取反.
00000010 // 原码和反码下的 +210000010 // 原码下的 -211111101 // 反码下的 -2和原码一样, 反码的0有两种表示方式.
可以表示为
可以表示为
00000000 (+0), 也可以表示为 11111111 (-0).现代计算机常用的表示方式, 简化了硬件设计, 减法可以用加法电路完成.
补码消除了0有两种表示的问题.
补码消除了0有两种表示的问题.
正数和0与原码的正数表示相同.
负数表示为其反码表示加上1.
负数表示为其反码表示加上1.
00000010 // 原码和反码下的 +210000010 // 原码下的 -211111101 // 反码下的 -211111110 // 补码下的 -2http://graphics.stanford.edu/~seander/bithacks.html
JavaScript支持通过左移获得的最大幂是30, 超过30结果就会变成0或负数.
2 ** n// 等同于1 << nMath.floor(n)// 等同于~~nMath.ceil(n)// 等同于~~n + 1Math.floor(n)// 等同于~~n - 1Math.ceil(n)// 等同于~~n// isOdd(n)if (n % 2) { // ...}// 等同于if (n & 1) { // ...}无论被交换的两个数的符号如何, 都可以完成交换.
let a = 1let b = 2const temp = bb = aa = temp// 等同于let a = 1let b = 2a = a ^ bb = b ^ aa = a ^ bhttps://www.chessprogramming.org/BitScan
~(10011010) // (01100101)(10010011) & (00111101) // (00010001)(10010011) | (00111101) // (10111111)(10010011) ^ (00111101) // (10101110)(10001010) << 2 // (00101000)视编程语言而定, 对于有符号类型与无符号类型执行右移运算, 可能会有不同的结果.
一些编程语言设有专门的 无符号右移运算符
>>>.有符号右移在高位补符号位, 如果是1就补1, 如果是0就补0.
(10001010) >> 2 // (11100010) 补码表示下的有符号右移(补了2个1)无符号右移在高位补零.
(10001010) >> 2 // (00100010) 无符号右移JavaScript的位运算符在32位上工作, 在执行位运算时, 数值会被视作32位整数.
除无符号右移外的位运算符, 都将数值视作32位有符号整数来运算.
只有无符号右移运算符, 会将数值视作32位无符号整数来运算.
除无符号右移外的位运算符, 都将数值视作32位有符号整数来运算.
只有无符号右移运算符, 会将数值视作32位无符号整数来运算.
-1 >> 1 = -1 // 对-1进行有符号右移1位// -1的补码表示为 11111111 11111111 11111111 11111111// 右移1后, 补码表示仍为 11111111 11111111 11111111 11111111-1 >>> 1 = 2147483647 // 对-1进行无符号右移1位// -1的补码表示为 11111111 11111111 11111111 11111111// 右移1后, 补码表示为 01111111 11111111 11111111 11111111// 由于其最高位是0, 它被视为一个正数, 而正数的原码, 补码, 反码表示相同,// 因此01111111 11111111 11111111 11111110就是2^31-1.// 乘法number << n // number乘以2的n次幂// 除法number >> n // 如果number为非负值, number除以2的n次幂掩码是一种利用位运算操作二进制数的方法.
flags = 00001111MASK = 10110110 // 打开所有为1的位flags = flags | MASK // 10111111flags = 00001111MASK = 10110110 // 关闭所有为1的位flags = flags & ~MASK // 00001001flags = 00001111MASK = 10110110 // 取反所有为1的位flags = flags ^ MASK // 10111001flags = 00001111MASK = 00001001 // 检查第1位和第4位是否为1if ((flags & MASK) === MASK) { // 当位的值如掩码预期时为真 ...}C语言可以使用struct和unsigned int表示一种按二进制位存储的结构, 这在文件操作和网络通信中很有用.
struct box_props { bool opaque: 1; // 开关位 unsigned int fill_color: 3; // 只占3位的值 unsigned int: 4; // 填充位 bool show_border: 1; // 开关位 unsigned int border_color: 3; // 只占3位的值 unsigned int border_style: 2; // 只占2位的值 unsigned int: 2; // 填充位} // 一个长度为16位的结构