diff options
author | Kenta Murata <[email protected]> | 2024-02-27 09:37:03 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2024-02-27 09:37:03 +0900 |
commit | 54a5b829442eb7ed1f4a2794ebb26696cf784e64 (patch) | |
tree | 1bdb2b9212fc19faf9e7babd3e6324d6fb10aaee | |
parent | 89f0c0ceb5e5e20c56e63498521966c499b361a5 (diff) |
Handle zero-like imaginary part as zero in to_r (#9581)
Fixes [Bug #5179]
-rw-r--r-- | complex.c | 16 | ||||
-rw-r--r-- | spec/ruby/core/complex/to_r_spec.rb | 12 | ||||
-rw-r--r-- | test/ruby/test_complex.rb | 23 |
3 files changed, 45 insertions, 6 deletions
@@ -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. */ @@ -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); } diff --git a/spec/ruby/core/complex/to_r_spec.rb b/spec/ruby/core/complex/to_r_spec.rb index 4559921492..788027a500 100644 --- a/spec/ruby/core/complex/to_r_spec.rb +++ b/spec/ruby/core/complex/to_r_spec.rb @@ -34,8 +34,16 @@ describe "Complex#to_r" do 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 diff --git a/test/ruby/test_complex.rb b/test/ruby/test_complex.rb index 8817a62873..c0cfb73235 100644 --- a/test/ruby/test_complex.rb +++ b/test/ruby/test_complex.rb @@ -1054,6 +1054,29 @@ class Complex_Test < Test::Unit::TestCase 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]) |