3

我有一个 ActiveRecord 对象:

 s = Show.find 3980

Show 有一个lngDecimal 类型的列(精度 10,小数位数 7)。如果我打电话lngs

s.lng
#=> #<BigDecimal:7fac9a12ff40,'-0.821975E2',18(18)> 

一切都很好。但如果我这样做:

s.lng == -82.1975
#=> false

它回来了false!但是两者都是一样的!它与我的数据库列作为十进制有关吗?

4

2 回答 2

5

不要比较 FPU 十进制字符串分数是否相等

所以,在 1.8.7p330:

BigDecimal.new('-82.1975') == -82.1975
 => true

但是在 1.9.3p194 它是false.

问题是浮点或双精度值与包含小数的十进制常量的比较充其量是不可靠的。

很少有十进制字符串分数在二进制 FP 表示中具有精确值。*例如,在 0.01 和 0.99 之间,只有 0.25、0.50 和 0.75 具有不重复的精确二进制表示。这大约是 BigDecimal 存在的一半原因。(另一半原因是FP数据的固定精度。)

因此,将实际机器值与十进制字符串常量进行比较时得到的结果取决于二进制小数中的每一位……低至 1/2 52 ……甚至需要四舍五入。

如果产生数字的过程、输入转换代码或其他任何涉及的过程有任何不完美的地方(呵呵,有点,抱歉),它们看起来不会完全相等。

可以提出一个论点,即比较应该总是失败,因为没有 IEEE 格式的 FPU 甚至可以准确地表示该数字。

多年来,MySQL 和 ActiveRecord 已经改变了处理带分数的数字的确切方式。

但是可以肯定的是,您不需要将浮点数与 BigDecimal 混合,即选择:

BigDecimal.new('-82.1975')

并与之进行比较。


*问题:机器编号是 x/2 n,但十进制常数是 x/(2 n * 5 m )。

于 2012-12-24T22:29:15.443 回答
0

请试试s.lng.to_f == -82.1975

于 2012-12-24T21:43:32.593 回答