Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
内部舍入问题:计算Ruby浮点数的精确方法?_Ruby - Fatal编程技术网

内部舍入问题:计算Ruby浮点数的精确方法?

内部舍入问题:计算Ruby浮点数的精确方法?,ruby,Ruby,这当然是不正确的: (0.1 + 0.1 + 0.1) => 0.30000000000000004 (0.1 + 0.1 + 0.1) == 0.3 # false 我不需要一个完美的和,只需要说两个浮点数是相同的值。我能想出的最好办法是将方程的两边相乘,然后取整。这是最好的方式吗 ((0.1 + 0.1 + 0.1) * 1000).round == (0.3 * 1000).round 更新:我坚持使用Ruby v1.8.7。舍入方法支持指定要舍入的小数位数: 所以 。。。

这当然是不正确的:

(0.1 + 0.1 + 0.1) => 0.30000000000000004

(0.1 + 0.1 + 0.1) == 0.3   # false
我不需要一个完美的和,只需要说两个浮点数是相同的值。我能想出的最好办法是将方程的两边相乘,然后取整。这是最好的方式吗

((0.1 + 0.1 + 0.1) * 1000).round == (0.3 * 1000).round

更新:我坚持使用Ruby v1.8.7。

舍入方法支持指定要舍入的小数位数:

所以


。。。应该是好的。

准确求和和和有效比较是有区别的。你说你想要前者,但看起来你想要后者。底层的Ruby float算法是IEEE,它具有使累积错误最小化的合理语义,但当使用不能准确表示所有值的表示时,总会出现这种情况。为了精确地模拟误差,FP加法不应该产生精确的值,它应该产生一个区间,进一步的加法将对区间进行运算

在实践中,许多应用程序不需要对错误进行详细说明,它们只需要进行计算,并意识到比较并不精确,输出的十进制表示应该四舍五入

这里有一个简单的Float扩展,可以帮助您进行比较。它或类似的东西应该在stdlib中,但不是

class Float
  def near_enough?(other, epsilon = 1e-6)
    (self - other.to_f).abs < epsilon.to_f
  end
end

pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3)
=> true
pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3, 1e-17)
=> false
pry(main)> ( [0.1] * (10**6) ).reduce(:+).near_enough?(10**5, 1e-5)
=> true
pry(main)> ( [0.1] * (10**6) ).reduce(:+).near_enough?(10**5)
=> false

浮点比较通常是通过
来完成的,如果abs(v1-v2)是真的。这可能是我听过的最好的简短回答:((0.1+0.1+0.1)-0.3)。abs<0.0001抱歉,我忘了提到我在Ruby 1.8.7上遇到了这种情况。
backport
gem应该把它带到那里。不要忘了提到你也可以使用Float::EPSILON。类似这样的方法。@vgoff
Float::EPSILON
不是一个好的通用EPSILON。我不知道这是不是你的博客,但是正如所说的,很多事情要考虑,并且绝对没有考虑不到1。如果我必须比较浮动,我通常会尝试确定精度级别,并比较误差幅度之间的差异。但仍然没有找到我最喜欢的方法。谢谢你的博客链接。
class Float
  def near_enough?(other, epsilon = 1e-6)
    (self - other.to_f).abs < epsilon.to_f
  end
end

pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3)
=> true
pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3, 1e-17)
=> false
pry(main)> ( [0.1] * (10**6) ).reduce(:+).near_enough?(10**5, 1e-5)
=> true
pry(main)> ( [0.1] * (10**6) ).reduce(:+).near_enough?(10**5)
=> false
pry(main)> r=Rational(1,10)
=> (1/10)
pry(main)> (r + r + r) == Rational(3,10)
=> true
pry(main)> (r + r + r) == 0.3
=> true
pry(main)> r.to_f
=> 0.1
pry(main)> (r + r + r).to_f
=> 0.3