MySQL round weird bug

前端 未结 2 1218
轮回少年
轮回少年 2020-12-11 18:43

I\'m facing a really weird ¿bug? on mysql+php right now. Is a simple select, in the following example i\'m using multiple fields to try to explain my problem:

相关标签:
2条回答
  • 2020-12-11 19:21

    The problem is how the DOUBLE and FLOAT values are stored.

    It is possible (and probable) that values like 11.5 or 22.475 coul be stored in approximated values like 11.499999999999~ or 22.475000000000000001 thus some calculations or roundings could lead to incorrect results.

    It is always better to store float values into a DECIMAL coulmn type where the value is stored exactly with all the decimal digits and is not approximated.

    0 讨论(0)
  • 2020-12-11 19:40

    Exact numeric literals (such as the 1.15 in all four of your examples and the 11.5 in your latter two) are encoded using MySQL's DECIMAL type.

    In your first two examples, the result of multiplying field (of type DOUBLE) with such literals is another DOUBLE, which is stored using 8-byte IEEE Standard floating-point representation (i.e. binary64). However, in this representation 13.225 encodes as 0x402A733333333333, whose bits signify:

    Sign           : 0b0
    
    Biased exponent: 0b10000000010
                   =   1026 (representation includes bias of +1023, therefore exp = 3)
    
    Significand    : 0b[1.]1010011100110011001100110011001100110011001100110011
                   =   [1.]6531249999999999555910790149937383830547332763671875
                        ^ hidden bit, not stored in binary representation
    

    This equates to:

      (-1)^0 * 1.6531249999999999555910790149937383830547332763671875 * 2^3
    =         13.2249999999999996447286321199499070644378662109375000
    

    Therefore, rounding this result to two decimal places yields 13.22 not 13.23.

    Performing the multiplication with two DECIMAL types, such as two literals as used in your latter two examples, results in another DECIMAL. In this representation, 13.225 encodes in a binary-coded decimal format with exact precision and therefore the rounding operation results in 13.23 as expected.

    As mentioned in the MySQL manual:

    Floating-point numbers sometimes cause confusion because they are approximate and not stored as exact values. A floating-point value as written in an SQL statement may not be the same as the value represented internally. Attempts to treat floating-point values as exact in comparisons may lead to problems. They are also subject to platform or implementation dependencies. The FLOAT and DOUBLE data types are subject to these issues. For DECIMAL columns, MySQL performs operations with a precision of 65 decimal digits, which should solve most common inaccuracy problems.

    If you are after exact precision, DECIMAL may be more suited to your requirements. If you need the range/performance of DOUBLE but still wish to have the desired rounding outcome, you could CONVERT the result of the multiplication to DECIMAL prior to rounding.

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