简体   繁体   English

加 0.1 + 0.1 时,浮点加法 go 究竟在哪里出错?

[英]Exactly where does floating point addition go wrong when adding 0.1 + 0.1?

I'm trying to find out why 0.1 + 0.1 +... 100 times equals 9.99999999999998我试图找出为什么 0.1 + 0.1 +... 100 次等于 9.99999999999998

I started by reasoning that 0.1 is represented by a 64 bit value as 1 X 10^-1.我首先推断 0.1 由 64 位值表示为 1 X 10^-1。 (1 bit for negative, (0), 11 bits for exponent (10000000001), 52 bits for negative fraction (0000....0001)) (1 位表示负数,(0),11 位表示指数(10000000001),52 位表示负数(0000....0001))

But when I think about floating point addition... I can't figure how it could mess this up.但是当我考虑浮点加法时......我不知道它怎么会搞砸。

Example 1: Notice how we have to limit precision when we convert fractions to Real numbers.示例 1:请注意,当我们将分数转换为实数时,我们必须如何限制精度。 Put 1/3 in a calculator and it will have to cut it off at some point: 1/3 = 0.333333333333333333... (Limit its precision)将 1/3 放入计算器中,它必须在某个时候将其切断:1/3 = 0.333333333333333333...(限制其精度)

Example 2: double sum= 0;示例 2:双和 = 0;

    for(int i=0;i<100;i++){
        sum+=0.1;    // 0.1 + 0.1 = 1.0 * 10^-1
    }
    System.out.println(sum); // = 9.99999999999998 because floating point addition is limited by precision in each step.

And because of this, the best way to compare the numbers is see if they are equal at some precision:正因为如此,比较数字的最佳方法是查看它们是否在某个精度上相等:

    double epsilon = 0.0000000000001;
    
    if(Math.abs(sum-10) < epsilon){

        System.out.println("Equal within epsilon"); // This one wins here
    } else {
        System.out.println("Not equal within epsilon");
    }

That's great but can someone tell me how under-the-hood, addition of 0.1 is going wrong?太好了,但是有人可以告诉我在幕后,添加 0.1 会出错吗?

That's great but can someone tell me how under-the-hood, addition of 0.1 is going wrong?太好了,但是有人可以告诉我在幕后,添加 0.1 会出错吗?

The problem is that when you use double to represent 0.1 , the actual value of the double is not exactly 0.1.问题是当你使用double来表示0.1时, double的实际值并不完全是0.1。 It is as close as possible to 0.1 as can be represented as a IEE 754 double precision value.它尽可能接近 0.1,可以表示为IEE 754 双精度值。 But it is "off" by a tiny amount... a "delta".但它是“关闭”了一小部分......一个“三角洲”。

(The actual double value for 0.1d is precisely 3602879701896397 / 2 55 .) (0.1d 的实际double精度值恰好是0.1d / 2 55 。)

So when you add the double representation of "almost by not exactly" 0.1 one hundred times, the sum you get is off by one hundred times the "delta".因此,当您将“几乎不完全”的double表示加 0.1 一百次时,您得到的总和是“增量”的一百倍。 That is large enough that 100 x 0.1d is not equal to 10 (or 10.0d ).这足够大,以至于 100 x 0.1d不等于10 (或10.0d )。

If you want a more detailed understanding, read Is floating point math broken?如果您想更详细地了解,请阅读浮点数学是否损坏? . . (Answer: no it isn't, but it is more complicated than you learned in high school.) (答案:不,不是,但它比你在高中学到的要复杂。)

If you want even more, read"What Every Computer Scientist Should Know About Floating-Point Arithmetic" by David Goldberg.如果您想了解更多信息,请阅读 David Goldberg的“每个计算机科学家应该了解的关于浮点运算的知识”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM