floating point issue

前端 未结 4 1854
醉梦人生
醉梦人生 2020-12-12 07:19

I have a floating value as 0.1 entering from UI.

But, while converting that string to float i am getting as 0.10...01. The problem is the appending of non zero dig

4条回答
  •  Happy的楠姐
    2020-12-12 07:52

    The best site I've ever seen that explains why some numbers can't be represented exactly is Harald Schmidt's IEEE754 Converter site.

    It's an online tool for showing representations of IEEE754 single precision values and I liked it so much, I wrote my own Java app to do it (and double precision as well).

    Bottom line, there are only about four billion different 32-bit values you can have but there are an infinite number of real values between any two different values. So you have a problem with precision. That's something you'll have to get used to.

    If you want more precision and/or better type for decimal values, you can either:

    • switch to a higher number of bits.
    • use a decimal type
    • use a big-number library like GMP (although I refuse to use this in production code since I discovered it doesn't handle memory shortages elegantly).

    Alternatively, you can use the inaccurate values (their error rates are very low, something like one part per hundred million for floats, from memory) and just print them out with less precision. Printing out 0.10000000145 to two decimal places will get you 0.10.

    You would have to do millions and millions of additions for the error to accumulate noticeably. Less of other operations of course but still a lot.


    As to why you're getting that value, 0.1 is stored in IEEE754 single precision format as follows (sign, exponent and mantissa):

    s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm    1/n
    0 01111011 10011001100110011001101
               ||||||||||||||||||||||+- 8388608
               |||||||||||||||||||||+-- 4194304
               ||||||||||||||||||||+--- 2097152
               |||||||||||||||||||+---- 1048576
               ||||||||||||||||||+-----  524288
               |||||||||||||||||+------  262144
               ||||||||||||||||+-------  131072
               |||||||||||||||+--------   65536
               ||||||||||||||+---------   32768
               |||||||||||||+----------   16384
               ||||||||||||+-----------    8192
               |||||||||||+------------    4096
               ||||||||||+-------------    2048
               |||||||||+--------------    1024
               ||||||||+---------------     512
               |||||||+----------------     256
               ||||||+-----------------     128
               |||||+------------------      64
               ||||+-------------------      32
               |||+--------------------      16
               ||+---------------------       8
               |+----------------------       4
               +-----------------------       2
    

    The sign is positive, that's pretty easy.

    The exponent is 64+32+16+8+2+1 = 123 - 127 bias = -4, so the multiplier is 2-4 or 1/16.

    The mantissa is chunky. It consists of 1 (the implicit base) plus (for all those bits with each being worth 1/(2n) as n starts at 1 and increases to the right), {1/2, 1/16, 1/32, 1/256, 1/512, 1/4096, 1/8192, 1/65536, 1/131072, 1/1048576, 1/2097152, 1/8388608}.

    When you add all these up, you get 1.60000002384185791015625.

    When you multiply that by the multiplier, you get 0.100000001490116119384765625, matching the double precision value on Harald's site as far as it's printed:

    0.10000000149011612 (out by 0.00000000149011612)
    

    And when you turn off the least significant (rightmost) bit, which is the smallest downward movement you can make, you get:

    0.09999999403953552 (out by 0.00000000596046448)
    

    Putting those two together:

    0.10000000149011612 (out by 0.00000000149011612)
                                          |
    0.09999999403953552 (out by 0.00000000596046448)
    

    you can see that the first one is a closer match, by about a factor of four (14.9:59.6). So that's the closest value you can get to 0.1.

提交回复
热议问题