Python floating point number comparison

前端 未结 3 1848
别跟我提以往
别跟我提以往 2020-12-03 05:58

I\'m just reviewing some basics of Python and there\'s a tricky problem about comparing floating point numbers.

2.2 * 3.0 == 6.6
3.3 * 2.0 == 6.6


        
相关标签:
3条回答
  • 2020-12-03 06:05

    It is also obvious that 3.3 * 2.0 is numerically identical to 6.6. The latter computation is nothing more than an increment of the binary exponent as it is the result of a multiplication with a power of two. You can see this in the following:

        | s exponent    significant
    ----+-------------------------------------------------------------------
    1.1 | 0 01111111111 0001100110011001100110011001100110011001100110011010
    2.2 | 0 10000000000 0001100110011001100110011001100110011001100110011010
    3.3 | 0 10000000000 1010011001100110011001100110011001100110011001100110
    6.6 | 0 10000000001 1010011001100110011001100110011001100110011001100110
    

    Above you see the binary representation of the floating point numbers 3.3 and 6.6. The only difference in the two numbers is the exponent since they are only multiplied with two. We know that IEEE-754 will:

    • approximate a decimal number with the smallest numerical error
    • can represent all integers up to 2^53 exactly (for binary64)

    So since 2.0 is exactly representable, a multiplication with this number will be nothing more than a change in the exponent. So all the following will create the same floating point numbers:

    6.6 == 0.825 * 16.0 == 1.65 * 4.0 == 3.3*2.0 == 13.2 * 0.5 == ...
    

    Does this mean that 2.2*3.0 is different from 6.6 because of the significant? No, this was just due to rounding errors in the multiplication.

    An example where it would have worked would have been 5.5*2.0 == 2.2*5.0 == 11.0. Here the rounding was favourable

    0 讨论(0)
  • 2020-12-03 06:19

    In order to complete Amadan's good answer, here is a more obvious way of seeing that 2.2*3. and 3.3*2. are not represented by the same float: in a Python shell,

    >>> 2.2 * 3.
    6.6000000000000005
    >>> 3.3 * 2.
    6.6
    

    In fact, the Python shell displays the representation of numbers, which by definition should allow the corresponding float to be correctly built back from the representation, so you see the numerical approximation of 2.2*3 that Python does. The fact that 2.2*3. != 3.3*2. is obvious when seeing all the necessary digits, like above.

    0 讨论(0)
  • 2020-12-03 06:20

    This might be illuminating:

    >>> float.hex(2.2 * 3.0)
    '0x1.a666666666667p+2'
    >>> float.hex(3.3 * 2.0)
    '0x1.a666666666666p+2'
    >>> float.hex(6.6)
    '0x1.a666666666666p+2'
    

    Although they are all displayed in decimal as 6.6, when you inspect the internal representation, two of them are represented in the same way, while one of them is not.

    0 讨论(0)
提交回复
热议问题