If I compare a
, b
and c
like so
[a,b,c].min
where
a = BigDecimal.new("NaN")
b = BigDecimal.new("NaN")
c = BigDecimal.new("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 min
, is there something else I can use to achieve the same effect as enumerable's min
that will not explode?
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
2025-05-18 edit:
Just in case anyone wants to drill down deeper on this question, the uniqueness of NaN is actually defined by IEEE 754 Standard for Floating Point Arithmetic, which Ruby simply follows.