为什么即使提供了准确的数据,FLOAT 类型的数据比较也不起作用

Sus*_*ang 5 sql sql-server floating-point precision sql-server-2012

在真实表中具有相同的值

SELECT * FROM float_value WHERE val = 49640.2473896214 -- No data returns
Run Code Online (Sandbox Code Playgroud)

如果我将其四舍五入到总精度,那么它就可以工作

SELECT * FROM float_value WHERE ROUND(val, 10) = ROUND(49640.2473896214, 10) --Returning Data
Run Code Online (Sandbox Code Playgroud)

之后,我创建了具有相同值的临时表49640.2473896214,它在上面失败的第一个查询中工作

CREATE TABLE #testing(Vvalue FLOAT)
INSERT INTO #testing VALUES (49640.2473896214)

SELECT * FROM #testing WHERE Vvalue = 49640.2473896214 -- Simply returning row
Run Code Online (Sandbox Code Playgroud)

您能帮我弄清楚为什么=上面的比较不起作用吗?如果我应该使用ROUNDalways,那么计算出要舍入和比较的精度将是另一个问题。

如果我们提供在字段中完全可见的输入,即= 49640.2473896214应该返回值,我想要结果。

先感谢您。

Sal*_*n A 4

浮点数不能完全按照您想要的方式表示值,例如:

  • 49640.2473896214321 存储为 49640.2473896214287378825247287750244140625
  • 49640.2473896214521 存储为 49640.247389621450565755367279052734375
  • 17.56 被存储为...留下作为练习

还值得注意的是,浮点数的显示值通常是一个近似值。某些环境允许您更改显示值的精度,但我在 SQL Server 中找不到任何此类设置。话虽如此:

SELECT * FROM float_value WHERE val = 49640.2473896214 -- No data returns
Run Code Online (Sandbox Code Playgroud)

那是因为49640.2473896214数据库中不存在。数据库中的值可能是...62139......62141...,谁知道呢。

您能帮我弄清楚为什么 = 比较在上面不起作用吗?

如果您提供数据库中存储的确切值(在之前的 INSERT 或 UPDATE 操作中使用),它应该可以工作。如果您提供在数据库中看到的值,请参阅上面的注释。

如果我应该始终使用 ROUND 那么计算要舍入和比较的精度将是另一个问题。

ROUNDing 返回 FLOAT for FLOAT,因此您最终可能会遇到类似的问题。该问题最常被引用的解决方案是将两个数字相减并检查差异是否非常小:

select * from #testing WHERE ABS(vvalue - 49640.24738962     ) < 1e-11
-- id | vvalue           | actual_value
-- 1  | 49640.24738962   | 49640.24738962

select * from #testing WHERE ABS(vvalue - 49640.2473896214   ) < 1e-11
-- id | vvalue           | actual_value
-- 2  | 49640.2473896214 | 49640.2473896214

select * from #testing WHERE ABS(vvalue - 49640.2473896214321) < 1e-11
-- id | vvalue           | actual_value
-- 3  | 49640.2473896214 | 49640.2473896214321

select * from #testing WHERE ABS(vvalue - 49640.2473896214521) < 1e-11
-- id | vvalue           | actual_value
-- 4  | 49640.2473896215 | 49640.2473896214521
Run Code Online (Sandbox Code Playgroud)

1e-11被称为 epsilon,即您可以接受的容差量。您可以将其设置为较小的值,但不能小于1e-16我所知的值。