Java For-loop 在改变循环变量类型时改变数值结果

Java For-loop changes numeric result when changing type of loop variable

我写了一个用莱布尼茨公式计算圆周率的程序:

[

我写了一个初始化类型为 "int" 的 for 循环,循环工作正常,但是当我将初始化类型更改为 "long" 时,结果发生了变化。只有当循环次数超过 10 亿次时才会发生这种情况。这使得 "int - loop" 计算 PI 比 "long - loop" 更准确。我不知道为什么会这样。请帮助我理解这个问题。谢谢!这是我的代码。

public static void main(String[] args) {
    double result1 = 0;
    double result2 = 0;
    double sign = 1;

    for (int i = 0; i <= 1607702095; i++) {
        result1 += sign/(2 * i + 1);
        sign *= -1;
    }
    sign = 1;

    for (long j = 0; j <= 1607702095; j++) {
        result2 += sign/(2 * j + 1);
        sign *= -1;
    }

    System.out.println("result1  " + result1 * 4);
    System.out.println("result2  " + result2 * 4);
    System.out.println("pi       " + Math.PI);
}

结果是:

result1  3.141592653576877
result2  3.1415926529660116
pi       3.141592653589793

实际上,当 i 足够大时,您的第一个循环会在 (2 * i + 1) 的计算中出现 int 溢出,因此我不会依赖它的输出。

另一方面,第二个循环产生更正确的输出,因为 (2 * j + 1) 不会溢出,因为它执行 long 乘法。

This makes the "int - loop" calculates PI more accurate than "long - loop"

这可能只是巧合,因为 int 循环中的计算溢出了。

2 * ii 接近循环结束时 会溢出最大值 int2147483647.

使用 long 操作不会溢出。

正确的步骤是使用 long 类型。可能是因为一些奇怪的行为在正确的 PI 周围添加和删除了值,溢出暂时计算到更接近正确的 PI 的值。

我想改变几个值的for循环的限制会使最终结果与正确的PI相差更远。

因为你在

行溢出了
result1 += sign/(2 * i + 1);

其中 2*i 的值超过最大整数值

int 范围是 -2,147,483,648 to 2,147,483,647,但是当您 2*i 以获得更大的值时,它会越过该范围。

最好坚持使用 long,这会给你正确的输出。

您有整数溢出

signed int 的最大容量为 (2^31)-1,即 2,147,483,647。

(1,607,702,095 * 2) 为 3215404190,大于 2,147,483,647。

当您将 i 更改为 long 时,您会将 i 的容量增加到 (2^63)-1。

注意到每个人都在指出整数溢出问题,但您可能需要一个解决方案。 (如果你已经有了,请忽略以下内容:) )

在代码的 (2 * i + 1) 部分出现溢出,您应该将 for 循环中的 i 最大为 (Integer.MAX_VALUE / 2 - 1),这将导致:

for (int i = 0; i <= (Integer.MAX_VALUE / 2 - 1); i++) {
    result1 += sign/(2 * i + 1);
    sign *= -1;
}

您也可以使用 (Long.MAX_VALUE / 2 - 1) 对较长的部分执行此操作,但它将 运行 持续很长时间。