我需要使用按位运算符执行某些操作,假设我们有这个 40 位无符号整数:
1071698660929
当我申请时 OR
运算符和无符号右移运算符我得到了这个负整数
输入:(1071698660929 >>> 0) | 0b0
输出:-2043163071
我注意到只要数字是 31 位长,添加 0B0
就没有任何问题。但是当数字大于 31 位时,即使我使用无符号右移运算符,它也会变为负数:
32位二进制返回-1
:(0b11111111111111111111111111111111 >>> 0) | 0
31位二进制返回2147483647
:(0b1111111111111111111111111111111 >>> 0) | 0
所以我有几个问题:
- 如果我使用右移运算符,为什么上面的数字会变成负数?我的理解是 javascript 中的 MAX 安全整数是 53 位长
Number.MAX_SAFE_INTEGER.toString(2).length
所以我在整数安全边界内。 - 我该怎么做才能做到这一点
(1071698660929 >>> 0) | 0b0
返回1071698660929
而不是-2043163071
?
最佳答案
按位运算符将其操作数隐式转换为 32 位整数(有符号或无符号,取决于运算符)。在此过程中,超过 32 位的数字将获得其最高有效位 discarded :
Before: 11100110111110100000000000000110000000000001
After: 10100000000000000110000000000001
此规则的唯一异常(exception)是(相对)原始 block 上的新 child ,BigInt类型:所有按位操作(&
、|
、^
)和几乎所有移位都是 overloaded对于该类型。
这为您的问题开辟了一条出路:只需使用 BigInt
而不是普通的 number
,或者显式地使用,如下所示:
const bigIntee = BigInt(1071698660929); // note no `new` here!
...或者,如果您实际上必须使用文字,请在其后面附加 n
:
const bigIntee = 1071698660929n; // also works
请注意,如果一个操作数是 BigInt
,则另一个操作数也应该是 BigInt
。所以这...
bigIntee | 0
...会让 JS 对你试图回到 90 年代快乐的类型无政府时代的可悲尝试感到愤怒。更具体地说,你会收到一个 TypeError 错误:
Cannot mix BigInt and other types, use explicit conversions
不过,这很容易解决:只需将上述转换技巧也应用于第二个操作数即可。
bigIntee | 0n
// or bigIntee | BigInt(0)
两者都有效。忽略 0
并不是真正的 Biggus Integerus 类型;类型安全在这里占主导地位。
仍然存在一个问题:>>>
(无符号右移运算符)不能在 BigInt 上使用。如果您尝试这样做,您将收到一个非常具体的错误:
bigIntee >>> 0n
// Uncaught TypeError: BigInts have no unsigned right shift, use >> instead
...这完全有道理(我们希望 JS 抛出的所有错误都是特定的)。
关于javascript - 与 0b 的按位或运算将给定数字转换为负数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73169169/