我们知道Java 不处理下溢和上溢,但是 Javascript 是如何处理整数的呢?
它会回到最小值/最大值吗?如果是,哪个最小值/最大值?
我需要拆分一个字符串并根据其字符计算一个哈希值。
在一个简单的测试中,当我尝试这个时:
var max = Number.MAX_VALUE;
var x = max + 10;
var min = Number.MIN_VALUE;
var y = min / 10;
我发现它x
具有max
相同的值(在 Chrome、IE 和 Firefox 中),所以看起来一些溢出只是与最大值挂钩。而且,y
被挂钩,0
所以一些下溢似乎归零。
啊,但事情没那么简单。并非所有上溢都转到Number.MAX_VALUE
,也不是所有下溢都转到Number.MIN_VALUE
。如果你这样做:
var max = Number.MAX_VALUE;
var z = max * 2;
那么,z
将Infinity
。
事实证明,这取决于您上溢/下溢的程度。如果你走得太远,你会得到 INFINITY。这是因为使用了 IEEE 754 舍入到最近的模式,其中最大值可以被认为比无穷大更接近。有关详细信息,请参阅添加到 Number.MAX_VALUE。根据该答案, 1.7976931348623158 × 10 308或更大的值四舍五入到无穷大。Number.MAX_VALUE 之间的值将四舍五入为 Number.MAX_VALUE。
为了让事情变得更加复杂,还有一些 Javascript 支持的逐渐下溢。这是浮点值的尾数有前导零的地方。逐渐下溢允许浮点表示一些较小的数字,没有它就无法表示,但它们以降低的精度表示。
您可以确切地看到限制在哪里:
>>> Number.MAX_VALUE + 9.979201e291
1.7976931348623157e+308
>>> Number.MAX_VALUE + 9.979202e291
Infinity
这是一个可运行的代码段,您可以在任何浏览器中尝试:
var max = Number.MAX_VALUE;
var x = max + 10;
var min = Number.MIN_VALUE;
var y = min / 10;
var z = max * 2;
document.getElementById("max").innerHTML = max;
document.getElementById("max10").innerHTML = x;
document.getElementById("min").innerHTML = min;
document.getElementById("min10").innerHTML = y;
document.getElementById("times2").innerHTML = z;
body {
font-family: "Courier New";
white-space:nowrap;
}
Number.MAX_VALUE = <span id="max"></span><br>
Number.MAX_VALUE + 10 = <span id="max10"></span><br>
<br>
Number.MIN_VALUE = <span id="min"></span><br>
Number.MIN_VALUE / 10 = <span id="min10"></span><br>
<br>
Number.MAX_VALUE * 2 = <span id="times2"></span><br>
最大值和最小值为+/- 9007199254740992
试试这些数字类型属性:
alert([Number.MAX_VALUE, Number.MIN_VALUE]);
来自 ECMAScript 2020 语言规范的“数字类型”部分:
请注意,所有大小不大于 2 53的正负数学整数都可以用 Number 类型表示(实际上,数学整数 0 有两种表示形式,+0 和 -0)。
测试:
var x = 9007199254740992;
var y = -x;
x == x + 1; // true !
y == y - 1; // also true !
Number
在 JavaScript 中,数字类型是 64 位 IEEE 754 浮点数,它不是整数。所以它不遵循其他语言中常见的整数溢出/下溢行为模式。
作为浮点数,基数部分使用 53 位。它可以表示范围Number.MIN_SAFE_INTEGER
为Number.MAX_SAFE_INTEGER
(-2 53 +1 到 2 53 -1) 的数字,而不会出现浮点错误。对于超出此范围的数字,它可能会四舍五入到最接近的可用数字,或者如果它太大,则可能是无穷大。
按位运算符处理操作数 32 位整数。常见的整数溢出可能与其他语言一样发生。计算后只能保留最后 32 位。例如,3<<31
将结果-2147483648
。
>>>
将操作数视为无符号 32 位整数。所有其他运算符将操作数视为带符号的 32 位整数。如果你想将有符号整数转换为无符号整数,你可以写value >>> 0
来解决这个问题。要转换回来,请使用value | 0
.
如果你想用 33 移动一个整数,它实际上会被移动 1。
BigInt
就像 Java 一样java.math.BigInteger
,BigInt
支持无界整数(但仍受内存限制)。所以这里可能永远不会发生整数溢出。
对于 TypedArray 类型,当分配的整数超出支持范围时,它会被截断,就像其他语言在转换整数时所做的那样,通过保留最低有效位。例如new Int8Array([1000])[0]
得到-24
.
此处适用于按位运算符的相同规则。该值将作为什么| 0
或>>> 0
做什么被运回。