实际类型的值比较不正确



我在db中有REAL类型的字段。我使用PostgreSQL。和查询

SELECT * FROM my_table WHERE my_field = 0.15

不返回my_field0.15的行。

但例如查询

SELECT * FROM my_table WHERE my_field > 0.15

工作正常。

如何解决此问题并获取带有my_field = 0.15的行?

若要解决您的问题,请改用数据类型numeric,它不是浮点类型,而是任意精度类型。

如果在numeric(相同单词,不同含义(列中输入数字文字0.15,则会存储确切的数量 - 与realfloat8列不同,在或列中,值被强制转换为下一个可能的二进制近似值。这可能准确,也可能不准确,具体取决于数量和实现细节。十进制数 0.15 恰好介于可能的二进制表示之间,并且存储时有一个微小的错误。

请注意,计算结果本身可能不精确,因此在这种情况下仍要警惕=运算符。

这也取决于您的测试方式。比较时,Postgres 强制将发散的数字类型转换为最能保存结果的类型。请考虑此演示

CREATE TABLE t(num_r real, num_n numeric);
INSERT INTO t VALUES (0.15, 0.15);
SELECT num_r, num_n  
     , num_r = num_n       AS test1           --> FALSE
     , num_r = num_n::real AS test2           --> TRUE
     , num_r - num_n       AS result_nonzero  --> float8
     , num_r - num_n::real AS result_zero     --> real
FROM   t;

db<>fiddle here
旧 sqlfiddle

因此,如果您已将0.15作为数字文字输入到数据类型为 real 的列中,则可以使用以下方式找到所有此类行:

SELECT * FROM my_table WHERE my_field = real '0.15'

如果需要精确存储小数位数,请使用numeric列。

您的问题源于 IEEE 754。

0.15不是0.15,而是0.15000000596046448(假设双精度(,因为它不能完全表示为二进制浮点数。

(检查此计算器(

为什么这是一个问题?在这种情况下,很可能是因为比较的另一方使用精确值 0.15 - 通过精确表示,如numeric类型。(根据埃里克的建议澄清(

所以有两种方法:

  • 使用一种实际以十进制格式存储数字的格式 - 正如 Erwin 所建议的那样
    • (或至少全面使用相同的类型(
  • 按照杰克的建议使用舍入 - 必须谨慎使用(顺便说一下,这也使用 numeric 类型,以准确表示 0.15......

推荐阅读:每个计算机科学家都应该知道的关于浮点运算的知识

(对不起,简短的回答...

好吧

,我看不到你的数据,但我猜my_field并不完全等于 0.15。尝试:

select * from my_table where round(my_field::numeric,2) = 0.15;

考虑到PPTerka和Jack的答案。

Approximate numeric data types do not store the exact values specified for many numbers;

在这里查看MS对实际值的解码。

http://technet.microsoft.com/en-us/library/ms187912(v=sql.105(.aspx

最新更新