为什么 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;
};

问题:

  1. 为什么 REPL 中的实际答案是 0?
  2. 我上面的算法有什么问题吗?

1 << 31 是一个 负数 ,其数量级很大,比标准浮点表示法所能表示的要大得多。因此 0 与实际值非常接近。

浮点计算机数学是一门极其复杂的学科。这不完全是魔术,但它非常复杂。一些语言提供某种 "fixed point" 十进制数学系统,以牺牲计算效率为代价允许无限的精度。 JavaScript 没有这样的内置工具。

至于迭代算法,发生的情况是当您将负值翻转回正值时,它太大而无法放入整数中。循环中的 >> 第一次出现时,您再次以负指数结束,因为 JavaScript 按位运算符强制内部转换为 32 位有符号整数。如果您换成 >>>,就不会遇到这个问题。