为什么我的 for 循环不会添加超过 1.0/10,000,000.0 的分数?

Why wont my for loop add fractions past 1.0/10,000,000.0?

我需要添加一系列分数。我查看了其他 for 循环以添加分数,但没有遇到我遇到的问题。分数分母每次增加 1.0,直到加起来为 1.0/1.0 + 1.0/2.0 + .... + 1.0/ 150,000,000.0。我的代码通过添加分数对我有用,直到我在我的 for 循环中超过 10,000,000。一旦我说 15,000,000 它就不会打印任何东西,程序继续 运行。我犯了什么错误?为什么超过一定数就不打印答案了?

代码如下:

float sum = 0;
float numerator = 1;
float denominator = 1;

for(float i = 1; i <= 10000000; i++)
{
    sum = ((float)numerator/denominator) + sum;
    denominator++;
}
System.out.println("The sum is " + sum);

1 添加到足够大的 float 将不再有任何效果。问题是 float 的精度有限——23 位。一旦达到大约 1600 万(大约 224),连续浮点值之间的差异大于 1。您可以通过打印出 Math.ulp 的结果看到这一点(单位在最后)值。

if (denominator % 1000 == 0)
    System.out.println("Denominator is " + denominator + ", ulp is " + Math.ulp(denominator));

在输出停止的点,ulp为1.0。

...
Denominator is 1.6775E7, ulp is 1.0
Denominator is 1.6776E7, ulp is 1.0
Denominator is 1.6777E7, ulp is 1.0

在224,ulp跳到2.0,加1.0按照IEEE的round towards even rule,和不变

将数据类型更改为 double 以获得更高的精度(53 位)。请注意,此更改只会延长问题,直到达到 253。这也会使您的程序 运行 更长 。如果您真的想超出这个数量,请使用 BigDecimals.

我的想法不是在这里写更多的评论:

浮点数的精度有限。这意味着如果你添加非常非常小的数字,结果可能不是你所期望的。它也以另一种方式工作 - 将 1 加到一个非常大的数字不会改变它的值。

在您的程序中,为避免此问题,您应该在求和之前递增整数值并将它们转换为浮点数。像这样:

public class Sum {

public static void main(String[] args) {
    // TODO Auto-generated method stub


    float sum = 0;
    float numerator = 1;
    int denominator = 1; //changed to int

    for(int i = 1; i <= 10000000; i++)
    {
        sum = (numerator/(float)denominator) + sum; //this casts denominator to float
        denominator++; //this will now increment integer

    }
    System.out.println("The sum is " + sum);




} 
}

进一步阅读:Floating point on wikipedia