MySQL圆奇怪的bug

ipr*_*net 6 php mysql

我面临着一个非常奇怪的错误?现在在mysql + php上.是一个简单的选择,在下面的例子中,我使用多个字段来尝试解释我的问题:

  • "场"是11.5
  • $ phpvar是1.15

MySQL查询:

select round(field * " . $phpvar . " ,2) as a1, 
       round(field * 1.15 ,2) as a2, 
       round(11.5 * " . $phpvar . " ,2) as a3, 
       round(11.5 * 1.15 ,2) as a4, 
       field * " . $phpvar . " as a5 
from ...
Run Code Online (Sandbox Code Playgroud)

好吧,我想要得到13.23."field" * $phpvar = 13.225,所以使用round(13.225,2)我应该得到13.23,对吗?好吧,是的,不.

查询结果:

  • a1 [round(field*".$ phpvar.",2)] => 13.22
  • a2 [round(field*1.15,2)] => 13.22
  • a3 [round(11.5*".$ phpvar.",2)] => 13.23
  • a4 [round(11.5*1.15,2)] => 13.23
  • a5 [field*".$ phpvar."] => 13.225(无圆)

我错过了什么?怎么可能,当谈到使用"领域"时,我的结果是假轮?

sha*_*yyx 8

问题是如何存储DOUBLE和FLOAT值.

有可能(并且可能)将像11.5或22.475这样的值存储在近似值中,如11.499999999999~或22.475000000000000001,因此某些计算或舍入可能导致不正确的结果.

将浮点值存储到DECIMAL coulmn类型中总是更好,其中值与所有十进制数字完全存储并且不是近似值.


egg*_*yal 5

精确的数字文字(例如1.15所有四个示例和11.5后两个示例)都使用MySQL的类型进行编码DECIMAL.

在前两个示例中,将field(类型DOUBLE)与这些文字相乘的结果是另一个DOUBLE,它使用8字节 IEEE标准浮点表示(即binary64)存储.但是,在此表示中13.225 编码为0x402A733333333333,其位表示:

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

这相当于:

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

因此,将此结果舍入到两位小数13.22不会产生13.23.

使用两种DECIMAL类型执行乘法,例如后两个示例中使用的两个文字,会产生另一种类型DECIMAL.在这个表示中,13.225编码在二进制编码的十进制具有精确的精度,因此在舍入运算结果格式13.23如预期.

正如MySQL手册中提到的:

浮点数有时会引起混淆,因为它们是近似值而不是存储为精确值.在SQL语句中写入的浮点值可能与内部表示的值不同.尝试将浮点值视为比较中的精确值可能会导致问题.它们还受平台或实现依赖性的影响.该FLOATDOUBLE数据类型都受到这些问题.对于DECIMAL列,MySQL执行精度为65位十进制数的运算,这可以解决最常见的不准确问题.

如果您精确精确,DECIMAL可能更适合您的要求.如果您需要范围/性能DOUBLE但仍希望获得所需的舍入结果,则可以CONVERTDECIMAL舍入之前乘以乘法的结果.