Skip to content

Commit

Permalink
Fix Float#<=> when other responds to infinite?
Browse files Browse the repository at this point in the history
Fixes `cmp` to support comparing infinity to rhs which responds to `infinite?`, and updates the spec to current upstream comparison spec.
  • Loading branch information
stevegeek committed Oct 25, 2022
1 parent b3c7d48 commit f4f6be7
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 6 deletions.
46 changes: 44 additions & 2 deletions spec/core/float/comparison_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
it "returns -1, 0, 1 when self is less than, equal, or greater than other" do
(1.5 <=> 5).should == -1
(2.45 <=> 2.45).should == 0
#((bignum_value*1.1) <=> bignum_value).should == 1
((bignum_value*1.1) <=> bignum_value).should == 1
end

it "returns nil when either argument is NaN" do
Expand All @@ -14,6 +14,9 @@

it "returns nil when the given argument is not a Float" do
(1.0 <=> "1").should be_nil
(1.0 <=> "1".freeze).should be_nil
(1.0 <=> :one).should be_nil
(1.0 <=> true).should be_nil
end

it "compares using #coerce when argument is not a Float" do
Expand Down Expand Up @@ -48,7 +51,7 @@ def coerce(other)

# The 4 tests below are taken from matz's revision 23730 for Ruby trunk
#
it "returns 1 when self is Infinity and other is a Bignum" do
it "returns 1 when self is Infinity and other is an Integer" do
(infinity_value <=> Float::MAX.to_i*2).should == 1
end

Expand All @@ -63,4 +66,43 @@ def coerce(other)
it "returns 1 when self is negative and other is -Infinity" do
(-Float::MAX.to_i*2 <=> -infinity_value).should == 1
end

it "returns 0 when self is Infinity and other other is infinite?=1" do
obj = Object.new
def obj.infinite?
1
end
(infinity_value <=> obj).should == 0
end

it "returns 1 when self is Infinity and other is infinite?=-1" do
obj = Object.new
def obj.infinite?
-1
end
(infinity_value <=> obj).should == 1
end

it "returns 1 when self is Infinity and other is infinite?=nil (which means finite)" do
obj = Object.new
def obj.infinite?
nil
end
(infinity_value <=> obj).should == 1
end

it "returns 0 for -0.0 and 0.0" do
(-0.0 <=> 0.0).should == 0
(0.0 <=> -0.0).should == 0
end

it "returns 0 for -0.0 and 0" do
(-0.0 <=> 0).should == 0
(0 <=> -0.0).should == 0
end

it "returns 0 for 0.0 and 0" do
(0.0 <=> 0).should == 0
(0 <=> 0.0).should == 0
end
end
20 changes: 16 additions & 4 deletions src/float_object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,23 @@ Value FloatObject::to_s() const {
}

Value FloatObject::cmp(Env *env, Value rhs) {
if (is_infinity() && rhs->is_integer() && rhs->as_integer()->is_bignum()) {
if (is_positive_infinity())
return Value::integer(1);
else
if (is_infinity()) {
if (rhs->is_integer() && rhs->as_integer()->is_bignum()) {
if (is_positive_infinity()) return Value::integer(1);
return Value::integer(-1);
}

auto is_infinite_symbol = "infinite?"_s;
if (rhs->respond_to(env, is_infinite_symbol)) {
auto rhs_infinite = rhs.send(env, is_infinite_symbol);
if (rhs_infinite->is_nil()) {
if (is_positive_infinity()) return Value::integer(1);
return Value::integer(-1);
}
auto rhs_infinite_int = rhs_infinite->as_integer()->to_nat_int_t();
int rhs_cmp = is_positive_infinity() ? (rhs_infinite_int > 0 ? 0 : 1) : (rhs_infinite_int < 0 ? 0 : -1);
return Value::integer(rhs_cmp);
}
}

Value lhs = this;
Expand Down

0 comments on commit f4f6be7

Please sign in to comment.