为什么 2 ** (1 << 31) == 0?
Why is 2 ** (1 << 31) == 0?
运行 这在节点 REPL 中,给我:
> 2 ** (1 << 31)
0
我还为此写了一个小算法,它给了我 1。
function pow(x, n) {
let res = 1;
let invert = false;
if (n < 0) { invert = true; n = -n; };
while (n > 0) {
if (n & 1)
res = res * x;
n = n >> 1; // n / 2
x = x * x;
}
if (invert) {
res = 1 / res;
}
return res;
};
问题:
- 为什么 REPL 中的实际答案是 0?
- 我上面的算法有什么问题吗?
值 1 << 31
是一个 负数 ,其数量级很大,比标准浮点表示法所能表示的要大得多。因此 0 与实际值非常接近。
浮点计算机数学是一门极其复杂的学科。这不完全是魔术,但它非常复杂。一些语言提供某种 "fixed point" 十进制数学系统,以牺牲计算效率为代价允许无限的精度。 JavaScript 没有这样的内置工具。
至于迭代算法,发生的情况是当您将负值翻转回正值时,它太大而无法放入整数中。循环中的 >>
第一次出现时,您再次以负指数结束,因为 JavaScript 按位运算符强制内部转换为 32 位有符号整数。如果您换成 >>>
,就不会遇到这个问题。
运行 这在节点 REPL 中,给我:
> 2 ** (1 << 31)
0
我还为此写了一个小算法,它给了我 1。
function pow(x, n) {
let res = 1;
let invert = false;
if (n < 0) { invert = true; n = -n; };
while (n > 0) {
if (n & 1)
res = res * x;
n = n >> 1; // n / 2
x = x * x;
}
if (invert) {
res = 1 / res;
}
return res;
};
问题:
- 为什么 REPL 中的实际答案是 0?
- 我上面的算法有什么问题吗?
值 1 << 31
是一个 负数 ,其数量级很大,比标准浮点表示法所能表示的要大得多。因此 0 与实际值非常接近。
浮点计算机数学是一门极其复杂的学科。这不完全是魔术,但它非常复杂。一些语言提供某种 "fixed point" 十进制数学系统,以牺牲计算效率为代价允许无限的精度。 JavaScript 没有这样的内置工具。
至于迭代算法,发生的情况是当您将负值翻转回正值时,它太大而无法放入整数中。循环中的 >>
第一次出现时,您再次以负指数结束,因为 JavaScript 按位运算符强制内部转换为 32 位有符号整数。如果您换成 >>>
,就不会遇到这个问题。