Javascript中~和~~运算符详解及相关二进制

269 阅读4分钟

我在leetcode上做第七题整数反转的时候,看到官方解法用到了~~ 。甚至不知道是干嘛的。写篇文章,加深下印象。

~操作符

1.什么是~操作符?

~是js的按位取反运算符,对数值的二进制原码的每一位进行翻转(1 变成 0,0 变成 1)。该运算符作用于32位整数。

2.~操作符运用

image.png

如图所示,整数在~运算符作用后,会取反再减一。也就是说

~x = -x - 1

这是为什么呢? 5的32位二进制为:

5 = 00000000 00000000 00000000 00000101

~5会对5的32位二进制进行取反

~5 = 11111111 11111111 11111111 11111010

因为是负值,11111111 11111111 11111111 11111010减一取反以后就是-6

~~ 操作符

~~ 操作符称双位非运算符,其作用就是对32位整数进行两次取反。对于整数是返回原始值。

image.png

实际运用

1. 本题中的应用

因为本题中使用点在x = ~~(x / 10),x为23位整数,正负未定,需要取整。这就体现了~~的第一个作用:取整。

image.png

作为取整,正数可以使用Math.floor(),不过~~双位非运算符计算更快,负数就不能使用Math.floor()

2. 处理非数值转换为数值

image.png

如果需要数值类型,可以对入参进行处理,不过别忘记了~0=-1

扩展

1. 仅作用于32位整数

32位有符号整数的数据范围为-2^31 ~ 2^31-1。即-2147483648 ~ 2147483647。因此处理边界值时,会出现错误。

image.png

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 000000001111111 11111111 11111111,即0-2147483647。其中有一个特殊值为0,对于0000000 00000000 000000001000000 00000000 00000000都表示0的话浪费了,因此当符号位为1时,值为-2147483648。因此负数(-2147483648~-1)比正数(1-2147483647)多了一位。

参考:JavaScript 的双位非运算(~~)JavaScript双位非运算 ~~是一个强大且经常被忽视的特性。它提供了一种 - 掘金

二进制中为什么负数是正数取反再加一 - marsggbo - 博客园

【JavaScript】位运算符 ~ 的作用详解_js中~-CSDN博客