【问题标题】:Floats in MySQLMySQL 中的浮点数
【发布时间】:2018-07-31 11:11:49
【问题描述】:

所以我有 2 个不同的查询,并且都有一个浮点数作为标准。 一个在应该返回的时候什么也不返回,另一个返回正确的值。

SELECT *
FROM filters 
WHERE hole = 0.7

什么都不返回

SELECT *
FROM filters 
WHERE ek = 66

返回

'143987', '1', '14', '45', '0.7', '66', '0'

0.7 符合预期。

但是下面

SELECT *
FROM needles 
WHERE needle_dia = 2.5

返回

'2', 'H1004', '300', '2.5', '2040173', '2040177'

我已检查它们是否具有完全相同的类型 - 无符号 FLOAT,不是非空,默认表达式 NULL。

这有什么原因吗?

我知道可以使用 DECIMAL 代替 FLOAT 的面孔,但我宁愿避免使用它。

【问题讨论】:

标签: mysql floating-point


【解决方案1】:

因为浮点编号系统是不连续的、不精确的,并且不能准确地表示某些值 (for example, 0.7),所以永远不应该比较浮点值是否相等。您应该始终使用 BETWEEN 表达式,并用合适的错误值括起来:

WITH cteEpsilon AS (SELECT 0.0001 AS EPSILON FROM DUAL)
SELECT *
  FROM filters f
  CROSS JOIN cteEpsilon e
  WHERE 0.7 BETWEEN f.hole - e.EPSILON
                AND f.hole + e.EPSILON

正如您在问题中指出的那样,更好的选择是使用精确的数字类型,例如 DECIMAL。


“什么?!?”,你说? “证明它!!!”

好的,很公平。让我们用一个简单的小程序,声明几个浮点常量,然后比较它们:

#include <stdio.h>

float  f = 0.7;
double d = 0.7;

int main()
  {
  if(f == d)
    printf("Equal\n");
  else
    printf("Not equal\n");

  printf("f = %60.50f\nd = %60.50f\n", f, d);
  }

现在 - 无需运行它或查看隐藏的盒子 - 预测输出并将您的预测写在一张纸上。

完成了吗?好的。编译并运行时,上面会产生:

不等于
f = 0.69999998807907104492187500000000000000000000000000
d = 0.69999999999999995559107901499373838300000000000000

没错 - 这里我们有两个常数,都指定为 0.7,它们彼此不相等。

这里的问题是,无论我们选择何种精度,0.7 都不能完全表示为 IEEE-754 浮点值。这里的常量有不同的精度——一个是 4 字节的浮点值(float 类型),第二个是“双精度”浮点值(double 类型),因为每个值的精度不同结果值不同。 (现在房间后面的聪明人说,“是的,但如果你使用整数,它们总是会正确比较”。不,聪明人 - 将常量更改为 1234567890 看看会发生什么。)你的编译器会尽可能产生最接近 0.7 的近似值,但该近似值仍不等于 0.7,并且与用于存储该值的变量的精度不同。这并不意味着 IEEE-754 坏了,你的电脑坏了,或者宇宙有一个通往 Candyland 的秘密陷阱门。 (Drat!:-) 这意味着浮点数比乍一看要复杂得多。我建议阅读以下内容以了解发生这种情况的原因:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

The Floating Point Gui.de

Why Are Floating Point Numbers Inaccurate,

Floating-Point Numbers: Issues and Limitations

Why Floating-Point Numbers May Lose Precision

【讨论】:

    【解决方案2】:

    嗯,可能是数据库解释错了。

    尝试这样的查询:

    SELECT *
    FROM filters 
    WHERE hole LIKE '0.7'
    

    如果它被视为一个字符串,这应该是独立的。

    【讨论】:

    • 非常感谢您的帮助。这似乎奏效了。我还尝试了另一个我遇到问题的值,1.2,它也在那里工作。我很想知道为什么它在一张桌子上有效,而在另一张桌子上无效。
    • 于是我做了一些实验。如果我将 2.5 从成功查询更改为 0.7 或 2.7,则不会返回任何结果。那么只有用 LIKE 才能得到正确的值。
    猜你喜欢
    • 1970-01-01
    • 2019-12-01
    • 2010-11-03
    • 2012-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多