比较 Ruby 中的浮点数时如何筛选出 NaN?

How do I screen out NaNs when comparing floats in Ruby?

我正在使用 Rails 5 和 Ruby 2.4。如何确定变量是否为数字?我以为 is_a?(Numeric) 是要走的路,但显然不适合我。我有这个代码

      puts "guesses arr: #{guesses_arr}"
      guesses_arr.map!{|str| str.is_a?(Numeric) && str == guesses_arr.max ? str : 0}

死于

guesses arr: [NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN]
ArgumentError: comparison of Float with NaN failed
    from /Users/davea/Documents/workspace/myproject/app/services/text_table_to_race_time_converter_service.rb:2121:in `max'
    from /Users/davea/Documents/workspace/myproject/app/services/text_table_to_race_time_converter_service.rb:2121:in `block (2 levels) in guess_headers_from_data_cols'
    from /Users/davea/Documents/workspace/myproject/app/services/text_table_to_race_time_converter_service.rb:2121:in `map!'

我无法在控制台中重现此内容,因为我似乎无法生成包含所有这些 "NaN" 值的数组。关键是,我如何确保在我的循环中不会比较那些?

您可以通过调用Float::NAN获得NaN:

[7] pry(main)> Float::NAN
=> NaN
[8] pry(main)> Float::NAN.nan?
=> true

如果您只想删除 NaN:

guesses_arr.reject! { |x| x.nan? }

例如:

[4] pry(main)> [1.0, Float::NAN].reject(&:nan?)
=> [1.0]

您可以在控制台中生成一个 NaN 值数组,如下所示:

[ 0.0 / 0.0 ] * 3
# => [NaN, NaN, NaN]

不完全清楚您的代码在做什么,但可能值得注意的是 max 抛出异常,而不是相等性测试。顺便说一句,如果您尝试将每个数组值与最大值进行比较 - 您可能希望 maxmap 之外,以避免多次计算它。

在此处关于拒绝 NaNs 的其他答案的基础上,您可以将它们放在一起得到类似的东西:

# set up dummy data - 2 values and 3 NaNs
guesses_arr = [ 0.0 / 0.0 ] * 3 + [ 2.0, 3.0 ]
puts "guesses arr: #{guesses_arr}"
# => [NaN, NaN, NaN, 2.0, 3.0]

# remove NaNs in place
guesses_arr.reject!(&:nan?)
maximum = guesses_arr.max
guesses_arr.map!{|str| str.is_a?(Numeric) && str == maximum ? str : 0}
# => [ 0, 3.0 ]

编辑:如果您在数组中混淆了整数,请先尝试将它们转换为浮点数:

# set up dummy data - including floats and integers
guesses_arr = [ 0.0 / 0.0 ] * 3 + [ 2.0, 3.0, 0 ]
guesses_arr.map!(&:to_f).reject!(&:nan?)
# => [ 2.0, 3.0, 0.0 ]

我们可以做几件事。回答具体问题。

arr = [1.0, Float::NAN, "1.0", "1"]
arr.map(&:to_f).reject(&:nan?)

将是关于删除 NaN

的简明示例

假设您正试图从不一致的数据中获取最大值,首先我们需要使用如下方法对其进行清理,该方法会将字符串或整数转换为浮点数,否则return nil.

def to_number(maybe_a_number)
  Float(maybe_a_number)
rescue ArgumentError
  nil
end

假设我们有上面的方法

guesses_arr.map(&:to_number).max # or .min

也就是说,很难调试的原因是您有一个 .map! 导致 guesses_arr 在您移动时发生变化。 (通常我们避免使用标准库 bang 方法,因为它们的对象错误很难调试。