【问题标题】:MySQL round weird bugMySQL圆形奇怪的错误
【发布时间】:2023-03-14 04:05:01
【问题描述】:

我正面临一个非常奇怪的¿错误?现在在 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 ...

好的,我正在尝试获取 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 (无圆)

我错过了什么?怎么可能,在使用“字段”时,我的结果是假的?

【问题讨论】:

  • 字段在数据库中是如何定义的?
  • 选择字段 * 1.15 和 11.5 * 1.15 也不进行四舍五入,如 a6 和 a7 并发布结果。
  • 安杰尔“场”是双倍的;; jishi select field * 1.15 返回 13.225;;选择 11.5 * 1.15 返回 13.25;; Nick 据我所知,mysql 上的 ceil() 返回“不小于 X 的最小整数值”,不带小数
  • 我猜 DB 列中的 11.5 可能存储为 11.499999999999~ 因此 11.4999999999~ * 1.15 将是 13.224999999~ 因此 round(13.224999999999~, 2) 将导致 13.22。这取决于列类型。

标签: php mysql


【解决方案1】:

使用 MySQL 的 DECIMAL 类型的确切数字文字(例如所有四个示例中的 1.15 和后两个示例中的 11.5)是 encoded

在您的前两个示例中,将 fieldDOUBLE 类型)与此类文字相乘的结果是另一个 DOUBLE,它使用 8-byte IEEE Standard 浮点表示(即 @987654324 @)。然而,在这个表示中,13.225 编码为0x402A733333333333,其位表示:

签名 : 0b0 有偏指数:0b10000000010 = 1026(表示包括 +1023 的偏差,因此 exp = 3) 有效位 : 0b[1.]1010011100110011001100110011001100110011001100110011 = [1.]6531249999999999555910790149937383830547332763671875 ^ 隐藏位,不以二进制表示形式存储

这相当于:

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

因此,将此结果四舍五入到小数点后两位得到13.22 而不是13.23

使用两个DECIMAL 类型(例如后两个示例中使用的两个文字)执行乘法运算,会产生另一个DECIMAL。在此表示中,13.225 以精确精度的binary-coded decimal 格式编码,因此舍入运算结果如预期的那样13.23

MySQL manual中提到的:

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

如果您追求精确,DECIMAL 可能更适合您的要求。如果您需要 DOUBLE 的范围/性能,但仍希望获得所需的舍入结果,您可以在舍入之前将 CONVERT 乘以 DECIMAL 的结果。

【讨论】:

    【解决方案2】:

    问题在于如何存储 DOUBLE 和 FLOAT 值。

    11.5 或 22.475 之类的值有可能(也很可能)存储为近似值,例如 11.499999999999~ 或 22.4750000000000000001,因此某些计算或舍入可能会导致不正确的结果。

    最好将浮点值存储到 DECIMAL 列类型中,其中值与所有十进制数字完全存储,而不是近似值。

    【讨论】:

    • 谢谢,使用 DECIMAL 是正确的,我会牢记这一点以备不时之需
    • @ipronet 如果有帮助,请标记答案。谢谢!
    • @shadyyx 那么你什么时候使用 float 和 double 因为它们的存储方式不同?
    猜你喜欢
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    • 1970-01-01
    • 2016-07-28
    • 2016-05-28
    • 2011-08-17
    相关资源
    最近更新 更多