Skip to content

Commit

Permalink
Handle zero-like imaginary part as zero in to_r (#9581)
Browse files Browse the repository at this point in the history
Fixes [Bug #5179]
  • Loading branch information
mrkn committed Feb 27, 2024
1 parent 89f0c0c commit 54a5b82
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
16 changes: 12 additions & 4 deletions complex.c
Expand Up @@ -1841,9 +1841,11 @@ nucomp_to_f(VALUE self)
*
* Complex.rect(1, 0).to_r # => (1/1)
* Complex.rect(1, Rational(0, 1)).to_r # => (1/1)
* Complex.rect(1, 0.0).to_r # => (1/1)
*
* Raises RangeError if <tt>self.imag</tt> is not exactly zero
* (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
* (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>)
* and <tt>self.imag.to_r</tt> is not exactly zero.
*
* Related: Complex#rationalize.
*/
Expand All @@ -1852,9 +1854,15 @@ nucomp_to_r(VALUE self)
{
get_dat1(self);

if (!k_exact_zero_p(dat->imag)) {
rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
self);
if (RB_FLOAT_TYPE_P(dat->imag) && FLOAT_ZERO_P(dat->imag)) {
/* Do nothing here */
}
else if (!k_exact_zero_p(dat->imag)) {
VALUE imag = rb_check_convert_type_with_id(dat->imag, T_RATIONAL, "Rational", idTo_r);
if (NIL_P(imag) || !k_exact_zero_p(imag)) {
rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
self);
}
}
return f_to_r(dat->real);
}
Expand Down
12 changes: 10 additions & 2 deletions spec/ruby/core/complex/to_r_spec.rb
Expand Up @@ -34,8 +34,16 @@
end

describe "when the imaginary part is Float 0.0" do
it "raises RangeError" do
-> { Complex(0, 0.0).to_r }.should raise_error(RangeError)
ruby_version_is ''...'3.4' do
it "raises RangeError" do
-> { Complex(0, 0.0).to_r }.should raise_error(RangeError)
end
end

ruby_version_is '3.4' do
it "returns a Rational" do
Complex(0, 0.0).to_r.should == 0r
end
end
end
end
23 changes: 23 additions & 0 deletions test/ruby/test_complex.rb
Expand Up @@ -1054,6 +1054,29 @@ def test_to_r
assert_raise(RangeError){Rational(Complex(3,2))}
end

def test_to_r_with_float
assert_equal(Rational(3), Complex(3, 0.0).to_r)
assert_raise(RangeError){Complex(3, 1.0).to_r}
end

def test_to_r_with_numeric_obj
c = Class.new(Numeric)

num = 0
c.define_method(:to_s) { num.to_s }
c.define_method(:==) { num == it }
c.define_method(:<) { num < it }

o = c.new
assert_equal(Rational(3), Complex(3, o).to_r)

num = 1
assert_raise(RangeError){Complex(3, o).to_r}

c.define_method(:to_r) { 0r }
assert_equal(Rational(3), Complex(3, o).to_r)
end

def test_to_c
c = nil.to_c
assert_equal([0,0], [c.real, c.imag])
Expand Down

0 comments on commit 54a5b82

Please sign in to comment.