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

  • 相关阅读:
    CodeForces 543d Road Improvement
    UVA Foreign Exchange
    ZOJ 1825 Compound Words
    UVA 10125 Sumsets
    CodeForces
    32位linux(centos)下mongoDB的安装
    关于PHP 采集类
    关于微信支付零时工代码的修正方法
    微信公众号申请,微信支付全攻略 2
    简介CentOS与 Ubuntu的不同
  • 原文地址:https://www.cnblogs.com/Genesisx/p/7530420.html
Copyright © 2011-2022 走看看