【问题标题】:Infinity is returned when calculating average in array在数组中计算平均值时返回无穷大
【发布时间】:2017-10-17 22:55:05
【问题描述】:

为什么在尝试查找股票的平均交易量时,以下方法会返回无穷大:

class Statistics

    def self.averageVolume(stocks)
        values = Array.new
        stocks.each do |stock|
            values.push(stock.volume)
        end
        values.reduce(:+).to_f / values.size
    end

end

class Stock
    attr_reader :date, :open, :high, :low, :close, :adjusted_close, :volume
    def initialize(date, open, high, low, close, adjusted_close, volume)
        @date = date
        @open = open
        @high = high
        @low = low
        @close = close
        @adjusted_close = adjusted_close
        @volume = volume
    end

    def close
        @close
    end

    def volume
        @volume
    end
end

CSV.foreach(fileName) do |stock|
    entry = Stock.new(stock[0], stock[1], stock[2], stock[3], stock[4], stock[5], stock[6])
    stocks.push(entry)
end

以下是方法的调用方式:

Statistics.averageVolume(stocks)

使用包含 251 行的文件输出到控制台:

stock.rb:32: warning: Float 23624900242507002003... out of range
Infinity

在以下行调用警告:values.reduce(:+).to_f / values.size

【问题讨论】:

  • 请提供minimal reproducible example,让我们确切知道警告发生在哪一行。
  • 警告发生在以下行values.reduce(:+).to_f / values.size
  • 在第 7 行的end 后面打断点,看看values 长什么样。
  • 除以零是一种快速破坏事物的好方法。如果那是一个空数组...
  • 专业提示:如果您有一个将 1:1 映射到函数参数的数组,请将其分解。 Stock.new(*stock) 不那么混乱。

标签: ruby average reduce infinity


【解决方案1】:

在编写平均函数时,您需要密切注意被零除的可能性。

这是一个固定的、更类似于 Ruby 的实现:

def self.average_volume(stocks)
  # No data in means no data out, can't calculate.
  return if (stocks.empty?)

  # Pick out the `volume` value from each stock, then combine
  # those with + using 0.0 as a default. This forces all of
  # the subsequent values to be floating-point.
  stocks.map(&:volume).reduce(0.0, &:+) / values.size
end

在 Ruby 中,强烈建议将变量和方法名称保留在 x_y 形式中,例如此处的 average_volume。大写字母具有重要意义,表示类、模块和常量名称等常量。

您可以使用模拟股票测试此方法:

require 'ostruct'

stocks = 10.times.map do |n|
  OpenStruct.new(volume: n)
end

average_volume(stocks)
# => 4.5
average_volume([ ])
# => nil

如果您仍然获得无穷大,那可能是因为您在某处为 volume 设置了一个损坏的值,这让事情变得一团糟。您可以尝试将其过滤掉:

stocks.map(&:value).reject(&:nan?)...

测试与nan? 可能是您去除垃圾数据所需要的。

【讨论】:

  • 感谢您提供清晰的示例。我可以设法找到错误;每当创建新股票时,交易量都会以字符串形式存储。在字符串上使用 to_f 因此将其转换为浮点数解决了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-30
  • 2014-01-23
  • 2017-09-23
  • 2013-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多