Ruby on Rails How to Deal with Nan

ruby on rails how to deal with NaN

NaN is instance of Float. Use Float#nan? method.

>> nan = 0.0/0 # OR nan = Float::NAN
=> NaN
>> nan.class
=> Float
>> nan.nan?
=> true
>> nan.is_a?(Float) && nan.nan?
=> true
>> (nan.is_a?(Float) && nan.nan?) ? 0 : nan
=> 0

UPDATE

NaN could also be an instance of BigDecimal:

((nan.is_a?(Float) || nan.is_a?(BigDecimal)) && nan.nan?) ? 0 : nan

or

{Float::NAN => 0, BigDecimal::NAN => 0}.fetch(nan, nan)

how to make NaN value as the lowest when ordering Active Record objects?

apparently it is just the way postgresql ordering with NaN

the workaround for this is using SQL syntax to change the NaN into null then set an options to set the null value to be the last when ordering

 DownloadSpeed.order(Arel.sql("nullif(avg, 'NaN') desc nulls last"))

related questions :

Postgres order column with NaN values

Why do NULL values come first when ordering DESC in a PostgreSQL query?

Check if number is NaN

Quickest way is to use this:

under_the_test.to_f.nan? # gives you true/false e.g.:
123.to_f.nan? # => false
(123/0.0).to_f.nan? #=> true

Also note that only Floats have #nan? method defined on them, that's the reason why I'm using #to_f in order to convert result to float first.

Tip: if you have integer calculation that potentially can divide by zero this will not work:

(123/0).to_f.nan? 

Because both 123 and 0 are integers and that will throw ZeroDivisionError, in order to overcome that issue Float::NAN constant can be useful - for example like this:

return Float::NAN if divisor == 0
return x / divisor

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

You can produce an array of NaN values in the console like so:

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

It's not entirely clear what your code is doing, but it might be worth noting that it's the max which is throwing the exception, and not the equality test. Incidentally, if you are trying to compare each array value against the maximum value - you might want to max outside of the map, to avoid having to evaluate it multiple times.

Building on top the other answer here on rejecting NaNs, you can put it all together to get something like:

# 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 ]

Edit: if you have integers mixed up in the array, try converting them into floats first:

# 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 ]

How do I check if a var is NaN in ruby?

despite the fact I set "i" to "NaN", I'm getting the baffling output above.

This is the correct behaviour, in accordance with the IEEĘ754 specification. You'll find the same thing in any other language, assuming it has implemented the specification correctly.

# In Ruby:
Float::NAN == Float::NAN
#=> false

// In JavaScript:
NaN == NaN
// false

The specification also provides a list of recommended functions, which includes:

isnan(x) - a predicate for "x is a NaN", equivalent to "x ≠ x".

In ruby, this has been implemented as Float#nan?:

Float::NAN.nan?
#=> true

Under the hood, this is indeed asserting that x != x:

int
isnan(double n)
{
return double_ne(n, n);
}

static int
double_ne(double n1, double n2)
{
return n1 != n2;
}

Ruby division infinity/NaN should return 0

Very similar to: How can I redefine Fixnum's + (plus) method in Ruby and keep original + functionality?

class Float
alias_method :old_div, :/

def /(y)
return NAN if self == y && y == 0.0
return INFINITY if self == 1.0 && y == 0.0
self.old_div(y)
end
end

I know the code above might not be what you exactly want. Feel free to customize it the way you want =)

How to check if an array contains Float::NAN

To check, you can use:

[1, 2, 3, 'a', 'b', Float::NAN].any?{|item| item.respond_to?(:nan?) && item.nan?}

(or try, if you use Rails)

And as for why, take a look at What is the rationale for all comparisons returning false for IEEE754 NaN values?



Related Topics



Leave a reply



Submit