## Bug #3609

### Float Infinity comparisons in 1.9

Status: | Closed | ||
---|---|---|---|

Priority: | Normal | ||

Assignee: | - | ||

ruby -v: | ruby 1.9.1p429 (2010-07-02 revision 28523) [i386-darwin9] | Backport: |

**Description**

=begin

The way <=> works on pretty much everything in Ruby

is that if a <=> b return 0, 1, or -1, it completely

determines the entire set of comparisons

a==b, a>=b, a>b, a<=b, aa, b==a, b>=a, b>a, b<=a, b<a.

(and if it doesn't, a==b/b==a will be both true or both false,

everything else will raise exception or return false/nil)

Float Infinity in 1.9 but not 1.8 seems to violate that.

Comparing it with strange things returns 1 if it's on the left,

but raises exception in every other way.

inf = 1.0/0.0

inf <=> "foo" # => 1

"foo" <=> inf # ArgumentError: comparison of String with Float failed

This interacts even more strangely with very large bignums and the

"if bignum converts to float, it equals that float" thing Ruby currently does

.

inf=1.0/0.0

huge=10**500

Consistent either way:

inf >= huge # => true

huge <= inf # => true

inf < huge # => false

huge > inf # => false

Consistent only with mathematical interpretation

(or with "equal if converts, except for special cases

for infinities"):

inf <=> huge # => 1

huge<=> inf # => -1

huge < inf # => true

huge >= inf # => false

Consistent only with "equal if converts":

inf == huge # => true

huge == inf # => true

inf > huge # => false

inf <= huge # => true

Now I'd definitely prefer mathematical interpretation of floats,

to "equal if converts", but this just doesn't make any sense

no matter which way I look at it.

=end

### History

#### #1 Updated by Marc-Andre Lafortune about 5 years ago

**Category**set to*core*

=begin

I completely agree that Math::Float <=> "foo" should return nil.

The current behavior is due to r23742 which wanted to address the fact that Float::Infinity <=> BigDecimal("1.0E500") was returning 0 (I think, see rubydev:38681)

To fix Float::Infinity <=> "foo", the minimum that must be done is:

diff --git a/numeric.c b/numeric.c

index eb3d4be..daa5d6d 100644

--- a/numeric.c

+++ b/numeric.c

@@ -1038,7 +1038,7 @@ flo_cmp(VALUE x, VALUE y)

break;

default:

- if (isinf(a) && (!rb_respond_to(y, rb_intern("infinite?")) ||
- if (isinf(a) && (rb_respond_to(y, rb_intern("infinite?")) && !RTEST(rb_funcall(y, rb_intern("infinite?"), 0, 0)))) { if (a > 0.0) return INT2FIX(1); return INT2FIX(-1);

The fact that <=> is not consistent with <, etc, is also a problem that need to be fixed. Either the special treatment should be extended to the other comparison operators, or the special treatment for infinity should be removed from <=>

I believe the special treatment should be removed altogether:

diff --git a/numeric.c b/numeric.c

index eb3d4be..a6c5360 100644

--- a/numeric.c

+++ b/numeric.c

@@ -1038,11 +1038,6 @@ flo_cmp(VALUE x, VALUE y)

break;

default:

- if (isinf(a) && (!rb_respond_to(y, rb_intern("infinite?")) ||
- !RTEST(rb_funcall(y, rb_intern("infinite?"), 0, 0)))) {
- if (a > 0.0) return INT2FIX(1);
- return INT2FIX(-1);
- } return rb_num_coerce_cmp(x, y, rb_intern("<=>")); } return rb_dbl_cmp(a, b);

I understand the intent, but the fact is that Float::INFINITY is a very big value, but since it is the float representation of a lot of big real numbers, like 10**400, 10**40000 or even Infinity itself, I feel that r23742 introduces many inconsistencies. For example, currently:

1.0e200 ** 2 <=> BigDecimal("1.0e99999") # => 1

=end

#### #2 Updated by Nobuyoshi Nakada about 5 years ago

**Status**changed from*Open*to*Closed***% Done**changed from*0*to*100*

=begin

This issue was solved with changeset r28751.

Tomasz, thank you for reporting this issue.

Your contribution to Ruby is greatly appreciated.

May Ruby be with you.

=end

#### #3 Updated by Nobuyoshi Nakada about 5 years ago

**Assignee**set to*Yuki Sonoda***Status**changed from*Closed*to*Assigned*

=begin

=end

#### #4 Updated by Yusuke Endoh about 5 years ago

**Status**changed from*Assigned*to*Closed*

=begin

Backported at r28788.

=end

#### #5 Updated by Marc-Andre Lafortune about 5 years ago

**Status**changed from*Closed*to*Open***Assignee**deleted ()*Yuki Sonoda*

=begin

The patch fixes comparison with non numerics, but doesn't address the rest of the issues:

- inconsistency with mathematics

- inconsistency with other operators like <, <=, ..

Is there objection to removing the special test for infinity?

diff --git a/numeric.c b/numeric.c

index 740ef54..ed159ce 100644

--- a/numeric.c

+++ b/numeric.c

@@ -1039,15 +1039,6 @@ flo_cmp(VALUE x, VALUE y)

break;

default:

- if (isinf(a) && (i = rb_check_funcall(y, rb_intern("infinite?"), 0, 0)) != Qundef) {
- if (RTEST(i)) {
- int j = rb_cmpint(i, x, y);
- j = (a > 0.0) ? (j > 0 ? 0 : +1) : (j < 0 ? 0 : -1);
- return INT2FIX(j);
- }
- if (a > 0.0) return INT2FIX(1);
- return INT2FIX(-1);
- } return rb_num_coerce_cmp(x, y, rb_intern("<=>")); } return rb_dbl_cmp(a, b);

=end

#### #6 Updated by Yusuke Endoh about 5 years ago

**Target version**set to*2.0.0*

=begin

Hi,

The patch fixes comparison with non numerics, but doesn't address the rest of the issues:

Indeed. I thought nobu aimed to fix only the obvious wrong condition.

Is there objection to removing the special test for infinity?

It looks like a design issue rather then code bug. So I change this

to 1.9.x.

I have no objection against removal of the code in trunk. Though,

I like rather extend the special test to other operators than remove.

--

Yusuke Endoh mame@tsg.ne.jp

=end