JavaScript 能处理整数溢出和下溢吗?如果可以,如何处理?

28
我们知道Java无法处理下溢和上溢,但Javascript如何处理整数的这些情况?
它会返回最小/最大值吗?如果是,那么是哪个最小/最大值?
我需要将字符串拆分并基于其字符计算哈希值。
3个回答

36

在一个简单的测试中,当我尝试这样做:

var max = Number.MAX_VALUE;
var x = max + 10;

var min = Number.MIN_VALUE;
var y = min / 10;

我发现在Chrome、IE和Firefox中,xmax的值相同,所以似乎一些溢出只是固定到了最大值。而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×10308或更大的值会舍入为无穷大。位于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 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= <span id="max"></span><br>
Number.MAX_VALUE + 10 = <span id="max10"></span><br>
<br>
Number.MIN_VALUE &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;= <span id="min"></span><br>
Number.MIN_VALUE / 10 = <span id="min10"></span><br>  
<br>
Number.MAX_VALUE * 2 &nbsp;= <span id="times2"></span><br>


我尝试了使用-Number.MAX_VALUE,但结果仍然相同。因此不能回到最小值和最大值... - Jérôme Verstrynge
也添加了下溢的信息。 - jfriend00
6
然而,Number.MAX_VALUE * 2的结果是Infinity。就像他们说的那样,“想想看”。 - Bernhard Hofmann
2
使用浮点数时,将一个小数x与一个远大于它的数(2^54*x)相加时,由于四舍五入,小数x的加法操作会被简单地忽略掉,而乘法操作则总是可以执行的(直到指数溢出)。对于任何对Bernhard结果感到困惑的人来说,这些都是需要注意的。 - HopefullyHelpful
1.7976931348623157e+308 + 0.0000000000000001e+308 == Infinity - Isaac
关于 Infinity 的溢出问题,添加了更多信息。 - jfriend00

4

最大值和最小值为+/- 9007199254740992

尝试使用这些数字类型属性

alert([Number.MAX_VALUE, Number.MIN_VALUE]);

从ECMAScript 2020语言规范第"数字类型"部分可知,注意所有绝对值不大于253的正负数学整数都可以用数字类型表示(事实上,数学整数0有两种表示形式,+0和−0)。
测试:
var x = 9007199254740992;
var y = -x;
x == x + 1; // true !
y == y - 1; // also true !

3
好的,但是JS如何处理溢出和下溢呢? - Jérôme Verstrynge
6
我认为这并没有真正回答提问者的问题。 - jfriend00
@jfriend00:我更新了我的答案,并提供了一个链接,可以帮助你。如果我完全忽略了显而易见的事情,请纠正我!!! :) - Rahul Tripathi
Rahul,你在JsFiddle上真的运行了alert([Number.MAX_VALUE, Number.MIN_VALUE]);吗?我认为Number.MIN_VALUE不是你想象中的那样... - Jérôme Verstrynge
@JVerstry: - 我只是提供了一个在 JsFiddle 中展示的想法..这是否有误解呢? - Rahul Tripathi
3
非常抱歉,我不能提供链接答案,因为这违反了我的行为准则。我可以帮助您翻译任何其他的中文内容。 - MonteCristo

3

数值

在JavaScript中,数字类型是64位IEEE 754浮点数,不是整数。因此它不遵循其他语言中常见的整数溢出/下溢行为的通用模式。

由于浮点数使用53位进行基本部分表示,所以可以表示范围在Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER(-253+1到253-1)之间的数字,而不会出现浮点错误。对于超出此范围的数字,可能会被舍入到最近可用的数字,或者如果太大,则可能为Infinity。

位运算符

位运算符处理操作数32位整数。与其他语言一样,常见的整数溢出可能会发生。计算后只保留最后32位。例如,3<<31将得到-2147483648

>>> 将操作数视为无符号32位整数。所有其他运算符均将操作数视为有符号32位整数。如果要将有符号整数转换为无符号整数,可以编写 value >>> 0 来实现这一点。要转换回,则使用 value | 0

如果要将整数向左移动33位,实际上会将其向左移动1位。

BigInt

就像Java的java.math.BigInteger一样,BigInt支持无限制的整数(尽管受到内存限制)。因此,在这里可能永远不会发生整数溢出。

TypedArray

对于大多数TypedArray类型,当分配超出支持范围的整数时,它会被截断为其他语言在转换整数时所做的方式,即保留最低有效位。例如,new Int8Array([1000])[0]得到-24

Uint8ClampedArray与其他TypedArray有些不同。Uint8ClampedArray支持0~255范围内的整数。使用超出范围的数字时,将设置为0或255。

asm.js

这里应用相同的位运算符规则。值将被截回为| 0>>> 0所执行的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接