在浮点数中存储浮点数?
在Ruby核心库中,有一个非常有用的Set
类。它可以存储任何类型的对象。在浮点数中存储浮点数?
但是如你所知,浮点数(Ruby中的Float
)有一些精度问题。 1.2-1.0
并不等于0.2
。
s = Set.new()
s.add(1.2-1.0)
s.add(0.2)
s.size
=> 2
是的,我可以使用BigDecimal
类型来获得精确的数字。但是是否可以给Set
一个特定的比较函数,以便它能够承受一个小错误(例如,1e-9
)?
(我知道这个问题是不可知的语言。在其他常用的语言欢迎的解决方案)
有趣的问题,我想我已经找到了一个潜在的解决方案,这取决于你想要做什么。 Ruby使用引擎盖下的Hash
来存储Set
的元素。在Ruby中,Hash
键等于由方法hash
和eql?
定义。所以,如果你在Float
重新定义这些方法(!买者自负),可以使Set
考虑合理地接近Float
s到等于:
class Float
def eql?(other)
other.is_a?(Float) && self.round(9) == other.round(9)
end
alias :old_hash :hash
def hash
self.round(9).old_hash
end
end
s = Set.new
s.add(0.2)
s.include?(0.2) # => true
s.include?(1.2 - 1.0) # => true
s.include?(0.2001) # => false
“1.0000000004999999”和“1.0000000005000001”这两个花车怎么样?这两个浮点数尽可能地接近(假设IEEE 754和圆到最近点,则为1 ulp差值)。然而,他们在四舍五入到小数点后9位时会给出不同的结果。 – 2012-04-15 17:04:01
你说得对。这里的问题不是比较,而是'hash'方法。我们可以很容易地将比较结果改为'self - other tsherif 2012-04-15 17:28:30
“如果没有这些边界案例,我不认为这是可能的”。同意。一般来说,这是一个难以解决的问题。我的问题是为什么OP将Floats放入一个集合中...... – 2012-04-15 18:11:40
的语义是有问题的。例如,假设你已经有了'1.0'和'1.0 + 1.5e-9',允许的错误设置为'1e-9'。现在当你添加'1.0 + 0.7e-9'时会发生什么?该集合是从2个元素变为1个? – 2012-04-15 13:41:39