真实类型的值错误地比较

时间:2013-08-14 16:05:24

标签: sql postgresql types floating-point numeric

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

SELECT * FROM my_table WHERE my_field = 0.15

不会返回my_field的值为0.15的行。

但是例如查询

SELECT * FROM my_table WHERE my_field > 0.15

正常运作。

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

4 个答案:

答案 0 :(得分:13)

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

如果您输入numeric literal 0.15numeric(相同的字,不同的含义)柱,所述的确切量存储 - 不像用{ {1}}或real列,其中值被强制转换为下一个可能的二进制近似值。这可能是也可能不准确,具体取决于数量和实施细节。十进制数0.15恰好落在可能的二进制表示之间,并以很小的错误存储。

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

它还取决于你如何测试。比较时,Postgres将不同的数字类型强制转换为最能保持结果的类型。 考虑一下演示

=

<强> SQL Fiddle.

因此,如果您已将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; 作为数字文字输入到数据类型0.15的列中,则可以找到所有此类行:

real

如果您需要准确存储小数位数,请使用SELECT * FROM my_table WHERE my_field = real '0.15'列。

答案 1 :(得分:6)

您的问题来自IEEE 754

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

check this calculator

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

所以有两种方式:

  • 使用实际以十进制格式存储数字的格式 - 建议使用 Erwin
    • (或者至少在整个董事会中使用相同的类型)
  • 使用舍入作为杰克建议 - 必须谨慎使用(通过使用numeric类型的方式,以完全代表0.15 ...)

推荐阅读: What Every Computer Scientist Should Know About Floating-Point Arithmetic

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

同时考虑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