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