乘以浮点数会产生零

时间:2013-01-11 21:24:58

标签: ruby

下面的代码输出0.0。这是因为溢出?怎么避免呢?如果没有,为什么?

p ((1..100000).map {rand}).reduce :*

我希望加快这段代码:

p r.reduce(0) {|m, v| m + (Math.log10 v)}

并改为使用:

p Math.log10 (r.reduce :*)

但显然这并非总是可行......

3 个答案:

答案 0 :(得分:3)

rand生成的值都在0.0到1.0之间。这意味着在每次乘法时,您的数字会变小。因此,当你将它们乘以1000时,它可能与0无法区分。

在某些时候,ruby会将你的数字设为如此之小,以至于它为0.例如:2.0e-1000 # => 0

答案 1 :(得分:1)

每次乘法都会使你的数量减少大约 1/2 1 ,所以在大约50次之后,你会减少 1/2 50 < / sup>,,在100000之后(实际上,在大约700之后),你有 underflowed FP format itself, see here.

答案 2 :(得分:0)

Ruby提供了BigDecimal类,它实现了精确的浮点运算。

require 'bigdecimal'

n = 100

decimals = n.times.map { BigDecimal.new rand.to_s }
result = decimals.reduce :*

result.nonzero?.nil?  # returns nil if zero, self otherwise
# => false

result.precs  # [significant_digits, maximum_significant_digits]
# => [1575, 1764]

Math.log10 result
# => -46.8031931083014

然而,它比原生浮点数慢很多。 n = 100_000 decimals.reduce :*电话在我的计算机上停留了几分钟,然后我终于打断了它。