TheLegend TheLegend - 1 year ago 102
Ruby Question

Ruby Enumerable can't compare BigDecimal NaN in min function

If I compare

like so



a ="NaN")
b ="NaN")
c ="0.0")

I get:

ArgumentError: comparison of BigDecimal with BigDecimal failed

But if I was to use the comparison operator that ruby's Enumerable min uses then I get this:

irb(main):001:0> a <=> b
=> nil

irb(main):002:0> a <=> c
=> nil

And no errors are rendered. Is this an issue within Ruby or am I misunderstanding
, is there something else I can use to achieve the same effect as enumerable's
that will not explode?

Answer Source

From the Ruby language documentation:

NaN is never considered to be the same as any other value, even NaN itself:

n = ::new(‘NaN’)

n == 0.0 -> nil

n == n -> nil

As I understand it, any instance of the NaN value is unique and incomparable.

Consider this code snippet:

require 'bigdecimal'

a = BigDecimal('NaN')
b = BigDecimal('NaN')

puts a == b
puts a > b
puts a < b

You'll get false for each of these comparisons. min and max depend sorting to produce a result, and as @phoffer pointed out, sort produces values of 0, 1 and -1 based on whether the second number is equal to, greater than or less than the first number.

TL;DR: Any time you're using NaN in an operation, you can't expect meaningful results.

If the API you're working with returns NaN, you can at least protect yourself against this corner case by detecting it. NaN is actually an instance of Float, so you can test it by using the nan? method.

2.2.0 :002 > require 'bigdecimal'
 => true 
2.2.0 :003 > a = BigDecimal('NaN')
 => #<BigDecimal:7fae1b3bd050,'NaN',9(9)> 
2.2.0 :004 > a.nan?
 => true 
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download