所以我有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'


我检查了它们是否具有完全相同的类型-Unsigned FLOAT,不是非null,默认表达式为NULL。

可能有原因吗?

我知道可以使用DECIMAL代替FLOAT,但是我还是希望避免使用它。

最佳答案

因为浮点编号系统是不连续的,不精确的,并且不能精确地表示某些值(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

关于mysql - 在MySQL中 float ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51612028/

10-10 16:24