undur_gongor
undur_gongor

Reputation: 15954

Ruby: How to check for negative zero

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

Answers (5)

Tom Lord
Tom Lord

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

Patrick Oscity
Patrick Oscity

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

Rots
Rots

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

steenslag
steenslag

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

Tensho
Tensho

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

Related Questions