zoukankan      html  css  js  c++  java
  • Float精度丢失

    BigDecimal _0_1 = new BigDecimal(0.1);
    BigDecimal x = _0_1;
    for(int i = 1; i <= 10; i ++) {
        System.out.println(i+" x 0.1 is "+x+", as double "+x.doubleValue());
        x = x.add(_0_1);
    }
    

       输出:

    0.1000000000000000055511151231257827021181583404541015625, as double 0.1
    0.2000000000000000111022302462515654042363166809082031250, as double 0.2
    0.3000000000000000166533453693773481063544750213623046875, as double 0.30000000000000004
    0.4000000000000000222044604925031308084726333618164062500, as double 0.4
    0.5000000000000000277555756156289135105907917022705078125, as double 0.5
    0.6000000000000000333066907387546962127089500427246093750, as double 0.6000000000000001
    0.7000000000000000388578058618804789148271083831787109375, as double 0.7000000000000001
    0.8000000000000000444089209850062616169452667236328125000, as double 0.8
    0.9000000000000000499600361081320443190634250640869140625, as double 0.9
    1.0000000000000000555111512312578270211815834045410156250, as double 1.0
    

       原因:

    Most answers here address this question in very dry, technical terms. I'd like to address this in terms that normal human beings can understand.

    Imagine that you are trying to slice up pizzas. You have a robotic pizza cutter that can cut pizza slices exactly in half. It can halve a whole pizza, or it can halve an existing slice, but in any case, the halving is always exact.

    That pizza cutter has very fine movements, and if you start with a whole pizza, then halve that, and continue halving the smallest slice each time, you can do the halving 53 times before the slice is too small for even its high-precision abilities. At that point, you can no longer halve that very thin slice, but must either include or exclude it as is.

    Now, how would you piece all the slices in such a way that would add up to one-tenth (0.1) or one-fifth (0.2) of a pizza? Really think about it, and try working it out. You can even try to use a real pizza, if you have a mythical precision pizza cutter at hand. :-)


    Most experienced programmers, of course, know the real answer, which is that there is no way to piece together an exact tenth or fifth of the pizza using those slices, no matter how finely you slice them. You can do a pretty good approximation, and if you add up the approximation of 0.1 with the approximation of 0.2, you get a pretty good approximation of 0.3, but it's still just that, an approximation.

    For double-precision numbers (which is the precision that allows you to halve your pizza 53 times), the numbers immediately less and greater than 0.1 are 0.09999999999999999167332731531132594682276248931884765625 and 0.1000000000000000055511151231257827021181583404541015625. The latter is quite a bit closer to 0.1 than the former, so a numeric parser will, given an input of 0.1, favour the latter.

    (The difference between those two numbers is the "smallest slice" that we must decide to either include, which introduces an upward bias, or exclude, which introduces a downward bias. The technical term for that smallest slice is an ulp.)

    In the case of 0.2, the numbers are all the same, just scaled up by a factor of 2. Again, we favour the value that's slightly higher than 0.2.

    Notice that in both cases, the approximations for 0.1 and 0.2 have a slight upward bias. If we add enough of these biases in, they will push the number further and further away from what we want, and in fact, in the case of 0.1 + 0.2, the bias is high enough that the resulting number is no longer the closest number to 0.3.

    In particular, 0.1 + 0.2 is really 0.1000000000000000055511151231257827021181583404541015625 + 0.200000000000000011102230246251565404236316680908203125 = 0.3000000000000000444089209850062616169452667236328125, whereas the number closest to 0.3 is actually 0.299999999999999988897769753748434595763683319091796875.

      总结:

    这也解释通了0.1可以精确输出,0.3也可以精确输出 ,而0.1+0.1+0.1输出 0.30000000000000004;因为0.1 + 0.2实际上是0.1000000000000000055511151231257827021181583404541015625 + 0.200000000000000011102230246251565404236316680908203125 = 0.3000000000000000444089209850062616169452667236328125,而最接近0.3的数字实际上是0.299999999999999988897769753748434595763683319091796875。

        @Test
        public void test() {
            double a = 0.1;
            double b = 0.3;
            System.out.println("a:"+a);
            System.out.println("b:"+b);
            System.out.println("a+a+a:"+(a+a+a));
    
        }
    
    a:0.1
    b:0.3
    a+a+a:0.30000000000000004
    

    参考: https://stackoverflow.com/questions/588004/is-floating-point-math-broken

        https://stackoverflow.com/questions/26120311/why-does-adding-0-1-multiple-times-remain-lossless?noredirect=1

  • 相关阅读:
    太有才了!街头创意涂鸦手绘图片欣赏【上篇】
    设计前沿:25款精妙的 iOS 应用程序图标
    Web 前端开发精华文章集锦(jQuery、HTML5、CSS3)【系列十八】
    神奇的世界!那些使用食物创造出来的景观【组图】
    Screenfly – 各种设备的屏幕和分辨率下快速测试网站
    经典网页设计:30个新鲜出炉的扁平化网站设计《下篇》
    40款很奇异的名片设计,吸引你的眼球《下篇》
    推荐25款实用的 HTML5 前端框架和开发工具【下篇】
    CSS3 Animation Cheat Sheet:实用的 CSS3 动画库
    今日推荐:12个获取手机应用程序设计灵感的网站
  • 原文地址:https://www.cnblogs.com/Genesisx/p/7530420.html
Copyright © 2011-2022 走看看