Project

General

Profile

Actions

Bug #17098

closed

Float#negative? reports negative zero as not negative

Added by chrisseaton (Chris Seaton) about 1 year ago. Updated 4 months ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:99426]

Description

Is this intended behaviour?

irb(main):001:0> neg_zero = -0.0
=> -0.0
irb(main):002:0> neg_zero.negative?
=> false
irb(main):003:0> neg_zero < 0
=> false

It happens because Numeric#negative? uses < 0. My understanding of IEEE floating point is that negative zero is not less than zero, but I think it should still report as negative.

Updated by jeremyevans0 (Jeremy Evans) about 1 year ago

I disagree. By that logic, positive float zero should be positive (it isn't), and since -0.0 == 0.0 both should report as negative and positive, which is a contradiction.

Updated by chrisseaton (Chris Seaton) about 1 year ago

It's already the case that neg_zero == pos_zero but not all methods on the two returns the same result - for example neg_zero.inspect != pos_zero.inspect.

Updated by sawa (Tsuyoshi Sawada) about 1 year ago

chrisseaton (Chris Seaton) wrote in #note-2:

not all methods on the two [return] the same result - for example neg_zero.inspect != pos_zero.inspect.

What is your suggestion? To dispense with -0.0?

Updated by chrisseaton (Chris Seaton) about 1 year ago

My suggestion is that Float#negative?(neg_zero) == true and Float#positive?(pos_zero) == false.

We can't get rid of negative zero - it's a standard part of floating point numbers as implemented by the hardware. It's also useful in some applications.

Updated by chrisseaton (Chris Seaton) about 1 year ago

If people aren't keen on changing Float#negative? since it has existing semantics, then another option could be to add a new predicate Float#negative_zero? - that would allow people to differentiate as needed.

Updated by Eregon (Benoit Daloze) about 1 year ago

chrisseaton (Chris Seaton) wrote in #note-5:

then another option could be to add a new predicate Float#negative_zero? - that would allow people to differentiate as needed.

Interesting, I thought equal? would work for that (it does on TruffleRuby) but it does not on CRuby 2.6.6:

[19] pry(main)> 0.0.equal?(0.0)
=> true
[20] pry(main)> -0.0.equal?(-0.0)
=> false

I guess it's a result of implementing Float as tagged (flonum) but only for a subset of Float:

[25] pry(main)> a=-0.0
=> -0.0
[26] pry(main)> a.equal?(a)
=> true

eql? and == do not differentiate 0.0 and -0.0.

One way to test for -0.0 seems (-f).equal?(0.0) but that's kind of brittle as it relies on 0.0 being a flonum on CRuby.

I tend to agree that 0.0.positive? == -0.0.negative? and since 0.positive? => false then both as false seems to make sense (essentially they are the same as > 0 and < 0).

Updated by marcandre (Marc-Andre Lafortune) about 1 year ago

AFAIK, the only way to check for -0.0 is 1.0 / var == -Float::INFINITY

I find it difficult to discuss what need to be done about any of this as I do not know of the use cases for -0.0; without them it seems very theoretical.

Updated by sawa (Tsuyoshi Sawada) about 1 year ago

Ruby or IEEE 754 seem to regard -0.0 and 0.0 not as 0 in the mathematical sense, but as (something like) negative and positive infinitesimal. Taking this into account, I started to think -0.0.negative? and 0.0.positive? should both be true.

Regarding the fact that -0.0 == 0.0 is true, I think it should be understood as '-0.0 approaches 0.0' rather than '-0.0 is 0.0'. Then it would not contradict with the above. Floating point numbers are approximated numbers to begin with, so it does not make much sense to talk about their exact identity. Hence it makes sense to regard Float#== to mean 'close enough' rather than 'exactly the same'.

Updated by mrkn (Kenta Murata) 4 months ago

The current behavior is consistent with the behavior of the integer zero:

irb(main):001:0> 0.negative?
=> false
irb(main):002:0> 0.positive?
=> false

Updated by mrkn (Kenta Murata) 4 months ago

If you have pragmatic demands that need to distinguish -0.0 and +0.0, what do you think to propose the introduction of Float#signbit?

Updated by matz (Yukihiro Matsumoto) 4 months ago

Unless there's any particular (real-world) reason to distinguish floating positive zero and negative zero, I'd like to keep the current behavior.
And as mrkn (Kenta Murata) suggested, Float#sign may be useful to distinguish those two zeros, but it should be discussed as a different proposal.

Matz.

Actions #12

Updated by jeremyevans0 (Jeremy Evans) 4 months ago

  • Status changed from Open to Rejected
Actions

Also available in: Atom PDF