下面的代码输出 0.0。这是因为溢出吗?如何避免?如果不是,为什么?
p ((1..100000).map {rand}).reduce :*
我希望加快这段代码的速度:
p r.reduce(0) {|m, v| m + (Math.log10 v)}
并改用它:
p Math.log10 (r.reduce :*)
但显然这并不总是可能的......
下面的代码输出 0.0。这是因为溢出吗?如何避免?如果不是,为什么?
p ((1..100000).map {rand}).reduce :*
我希望加快这段代码的速度:
p r.reduce(0) {|m, v| m + (Math.log10 v)}
并改用它:
p Math.log10 (r.reduce :*)
但显然这并不总是可能的......
rand 产生的值都在 0.0 到 1.0 之间。这意味着每次乘法时,您的数字都会变小。因此,当您将它们乘以 1000 时,它可能与 0 无法区分。
在某些时候,ruby 会让你的数字变得如此之小以至于它是 0。例如:2.0e-1000 # => 0
每次乘法都会将您的数字减少约1/2 1,因此在其中约 50 次之后,您下降了1/2 50,并且在 100000 之后(实际上,在约 700 之后)您已经下溢了FP 格式本身,请参见此处。
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 :*
通话在我的电脑上持续了几分钟,然后我终于中断了它。