我在leetcode上做第七题整数反转的时候,看到官方解法用到了~~
。甚至不知道是干嘛的。写篇文章,加深下印象。
~操作符
1.什么是~操作符?
~是js的按位取反运算符,对数值的二进制原码的每一位进行翻转(1 变成 0,0 变成 1)。该运算符作用于32位整数。
2.~操作符运用
如图所示,整数在~运算符作用后,会取反再减一。也就是说
~x = -x - 1
这是为什么呢? 5的32位二进制为:
5 = 00000000 00000000 00000000 00000101
~5会对5的32位二进制进行取反
~5 = 11111111 11111111 11111111 11111010
因为是负值,11111111 11111111 11111111 11111010减一取反以后就是-6
~~ 操作符
~~ 操作符称双位非运算符,其作用就是对32位整数进行两次取反。对于整数是返回原始值。
实际运用
1. 本题中的应用
因为本题中使用点在x = ~~(x / 10),x为23位整数,正负未定,需要取整。这就体现了~~的第一个作用:取整。
作为取整,正数可以使用Math.floor(),不过~~双位非运算符计算更快,负数就不能使用Math.floor()
2. 处理非数值转换为数值
如果需要数值类型,可以对入参进行处理,不过别忘记了~0=-1
扩展
1. 仅作用于32位整数
32位有符号整数的数据范围为-2^31 ~ 2^31-1。即-2147483648 ~ 2147483647。因此处理边界值时,会出现错误。
2. 为什么负数需要正数原码取反后加一
2.1 例
取反后对应概念为反码,加一后变为补码。
比如3的八位二进制为0000 0011,-3就为11111101
2.2 为什么这么设计(简要版)
计算机中已经有电路实现加法运算,希望复用此电路实现减法运算。对于加法,直接二进制相加。对于减法,加上一个负数来实现。因此需要一个负数,怎么表示呢?就把第一位作为符号位,0表示正,1表示负。
那么怎么来确定负数的值呢?比如上方+3的八位二进制为0000 0011,那么-3+3是要等于0的。即
0000 0011+x=0000 0000。得出x=1111 1101,即为对应的正数原码取反后加一。
2.3 运算一致性
通过补码表示,负数可以直接通过加法运算。 例如-3+3:
0000 0011 + 1111 1101 = 1 0000 0000
由于是八位系统,运算后只取低八位,结果为0000 0000,即为0。
3. 为什么32位整数的数据范围为-2^31~2^31-1
32位整数的原码为00000000 00000000 00000000,首位为符号位,所以剩31位。0000000 00000000 00000000到1111111 11111111 11111111,即0-2147483647。其中有一个特殊值为0,对于0000000 00000000 00000000和1000000 00000000 00000000都表示0的话浪费了,因此当符号位为1时,值为-2147483648。因此负数(-2147483648~-1)比正数(1-2147483647)多了一位。
参考:JavaScript 的双位非运算(~~)JavaScript双位非运算 ~~是一个强大且经常被忽视的特性。它提供了一种 - 掘金