真实类型的值错误地比较

Mik*_*own 5 sql postgresql floating-point types numeric

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

SELECT * FROM my_table WHERE my_field = 0.15
Run Code Online (Sandbox Code Playgroud)

不返回行中的值my_field0.15.

但是例如查询

SELECT * FROM my_table WHERE my_field > 0.15
Run Code Online (Sandbox Code Playgroud)

工作正常.

如何解决此问题并获取行my_field = 0.15

Erw*_*ter 13

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

如果将数字文字 输入0.15numeric(相同的单词,不同的含义)列中,则会存储确切的数量 - 与a 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;
Run Code Online (Sandbox Code Playgroud)

SQL小提琴.

因此,如果您已0.15在数据类型列中输入数字文字real,则可以使用以下命令查找所有此类行:

SELECT * FROM my_table WHERE my_field = real '0.15'
Run Code Online (Sandbox Code Playgroud)

numeric如果您需要准确存储小数位,请使用列.


ppe*_*rka 6

您的问题源自IEEE 754.

0.15不是0.15,但是0.15000000596046448(假设是双精度),因为它不能精确地表示为二进制浮点数.

(查看此计算器)

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

所以有两种方法:

  • 使用一种实际以十进制格式存储数字的格式 - 正如Erwin建议的那样
    • (或者至少在整个板上使用相同的类型)
  • 杰克建议的那样使用舍入- 必须谨慎使用(顺便使用一种numeric类型的方式,准确代表0.15 ......)

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

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