Reputation: 15954
How can I find out if a Float
value is a negative zero (and not a positive one)?
Unfortunately:
-0.0 == 0.0 # => true
-0.0 === 0.0 # => true
My initial solution works but is ugly:
x.to_s == '-0.0'
From this question, I found
x == 0 and 1 / x < 0
Is there a better, more Ruby-like way?
Upvotes: 3
Views: 3022
Reputation: 28305
If your purpose is to prevent "negative zero", then this is how rails does it:
number = number.abs if number.zero?
Upvotes: 2
Reputation: 54684
Ruby's BigDecimal
class has a sign
method that produces the correct result for negative zero. You can convert a Float
to a BigDecimal
with the to_d
method if you require 'bigdecimal/util'
.
require 'bigdecimal'
require 'bigdecimal/util'
0.0.to_d.sign
#=> 1
-0.0.to_d.sign
#=> -1
Combine this with zero?
and you're good to go:
def negative_zero?(x)
x.zero? && x.to_d.sign == -1
end
negative_zero?(0.0)
#=> false
negative_zero?(-0.0)
#=> true
Upvotes: 7
Reputation: 5586
In Ruby the Float
equality operator for -0.0
and 0.0
returns true, as per ordinary arithmetic.
However if you convert the two floats to bytes using little-endian or big-endian byte order, you'll see they do not in fact match.
[-0.0].pack('E')
#=> "\x00\x00\x00\x00\x00\x00\x00\x80"
[0.0].pack('E')
#=> "\x00\x00\x00\x00\x00\x00\x00\x00"
[-0.0].pack('E') == [0.0].pack('E')
#=> false
Upvotes: 2
Reputation: 80065
The angle
method (and it's aliases arg
and phase
) returns zero for positive floats and Pi for negatives.
p 0.0.angle #=> 0
p -0.0.angle #=> 3.141592653589793
Upvotes: 4
Reputation: 893
Cause ruby determines them as the same object the only way to detect it by "-" sign after string conversion, as you described: -0.0.to_s.start_with?('-')
.
Upvotes: 0