Project

General

Profile

Bug #15857 » complex-real-spaceship.patch

jeremyevans0 (Jeremy Evans), 06/05/2019 04:53 AM

View differences:

complex.c
id_denominator, id_fdiv, id_numerator, id_quo,
id_real_p, id_i_real, id_i_imag,
id_finite_p, id_infinite_p, id_rationalize,
id_PI;
id_spaceship, id_PI;
#define id_to_i idTo_i
#define id_to_r idTo_r
#define id_negate idUMinus
......
return f_boolcast(f_eqeq_p(other, self));
}
static VALUE nucomp_real_p(VALUE self);
/*
* call-seq:
* cmp <=> object -> 0, 1, -1, or nil
*
* If +cmp+ is a real number (imaginary part is zero), and +object+ is also a
* real number, compare the real part of +cmp+ to object. Otherwise, return
* nil.
*
* Complex(2, 3) <=> Complex(2, 3) #=> nil
* Complex(2, 3) <=> 1 #=> nil
* Complex(2) <=> 1 #=> 1
* Complex(2) <=> 2 #=> 0
* Complex(2) <=> 3 #=> -1
*/
static VALUE
nucomp_cmp(VALUE self, VALUE other)
{
if (nucomp_real_p(self) && k_numeric_p(other) && f_real_p(other)) {
if (RB_TYPE_P(other, T_COMPLEX)) {
get_dat2(self, other);
return rb_funcall(adat->real, id_spaceship, 1, bdat->real);
} else {
get_dat1(self);
return rb_funcall(dat->real, id_spaceship, 1, other);
}
}
return Qnil;
}
/* :nodoc: */
static VALUE
nucomp_coerce(VALUE self, VALUE other)
{
if (k_numeric_p(other) && f_real_p(other))
return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
if (RB_TYPE_P(other, T_COMPLEX))
return rb_assoc_new(other, self);
if (k_numeric_p(other) && f_real_p(other))
return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
rb_raise(rb_eTypeError, "%"PRIsVALUE" can't be coerced into %"PRIsVALUE,
rb_obj_class(other), rb_obj_class(self));
......
/*
* call-seq:
* cmp.real? -> false
* Complex(1).real? -> true
* Complex(1, 1).real? -> false
*
* Returns false.
* Returns true if the imaginary part is zero, and false otherwise.
*/
static VALUE
nucomp_false(VALUE self)
nucomp_real_p(VALUE self)
{
return Qfalse;
get_dat1(self);
return(f_zero_p(dat->imag) ? Qtrue : Qfalse);
}
/*
......
id_finite_p = rb_intern("finite?");
id_infinite_p = rb_intern("infinite?");
id_rationalize = rb_intern("rationalize");
id_spaceship = rb_intern("<=>");
id_PI = rb_intern("PI");
rb_cComplex = rb_define_class("Complex", rb_cNumeric);
......
rb_define_method(rb_cComplex, "**", rb_complex_pow, 1);
rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
rb_define_method(rb_cComplex, "<=>", nucomp_cmp, 1);
rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
rb_define_method(rb_cComplex, "abs", rb_complex_abs, 0);
......
rb_define_method(rb_cComplex, "conjugate", rb_complex_conjugate, 0);
rb_define_method(rb_cComplex, "conj", rb_complex_conjugate, 0);
rb_define_method(rb_cComplex, "real?", nucomp_false, 0);
rb_define_method(rb_cComplex, "real?", nucomp_real_p, 0);
rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
spec/ruby/core/complex/real_spec.rb
Complex(2,3).real?.should be_false
end
it "returns false if there is not an imaginary part" do
Complex(2).real?.should be_false
end
ruby_version_is "2.7" do
it "returns false if there is not an imaginary part" do
Complex(2).real?.should be_true
end
it "returns false if the real part is Infinity" do
Complex(infinity_value).real?.should be_true
end
it "returns false if the real part is Infinity" do
Complex(infinity_value).real?.should be_false
it "returns false if the real part is NaN" do
Complex(nan_value).real?.should be_true
end
end
it "returns false if the real part is NaN" do
Complex(nan_value).real?.should be_false
ruby_version_is "" ... "2.7" do
it "returns false if there is not an imaginary part" do
Complex(2).real?.should be_false
end
it "returns false if the real part is Infinity" do
Complex(infinity_value).real?.should be_false
end
it "returns false if the real part is NaN" do
Complex(nan_value).real?.should be_false
end
end
end
test/ruby/test_complex.rb
c = Complex(1)
assert_not_predicate(c, :integer?)
assert_not_predicate(c, :real?)
assert_predicate(c, :real?)
assert_not_predicate(Complex(0,1), :real?)
assert_predicate(Complex(0), :zero?)
assert_predicate(Complex(0,0), :zero?)
......
end
def test_cmp
assert_raise(NoMethodError){1 <=> Complex(1,1)}
assert_raise(NoMethodError){Complex(1,1) <=> 1}
assert_raise(NoMethodError){Complex(1,1) <=> Complex(1,1)}
assert_nil(Complex(5, 1) <=> Complex(2))
assert_nil(5 <=> Complex(2, 1))
assert_equal(1, Complex(5) <=> Complex(2))
assert_equal(-1, Complex(2) <=> Complex(3))
assert_equal(0, Complex(2) <=> Complex(2))
assert_equal(1, Complex(5) <=> 2)
assert_equal(-1, Complex(2) <=> 3)
assert_equal(0, Complex(2) <=> 2)
end
def test_eqeq
assert_equal(Complex(1), Complex(1,0))
assert_equal(Complex(-1), Complex(-1,0))
......
def test_respond
c = Complex(1,1)
assert_not_respond_to(c, :%)
assert_not_respond_to(c, :<=>)
assert_not_respond_to(c, :div)
assert_not_respond_to(c, :divmod)
assert_not_respond_to(c, :floor)
test/ruby/test_complexrational.rb
assert_equal(Complex(SimpleRat(4,3),SimpleRat(1,1)), c * 2)
assert_equal(Complex(SimpleRat(1,3),SimpleRat(1,4)), c / 2)
assert_equal(Complex(SimpleRat(7,36),SimpleRat(2,3)), c ** 2)
assert_raise(NoMethodError){c <=> 2}
assert_nil(c <=> 2)
assert_equal(Complex(SimpleRat(8,3),SimpleRat(1,2)), 2 + c)
assert_equal(Complex(SimpleRat(4,3),SimpleRat(-1,2)), 2 - c)
......
r = 2 ** c
assert_in_delta(1.4940, r.real, 0.001)
assert_in_delta(0.5392, r.imag, 0.001)
assert_raise(NoMethodError){2 <=> c}
assert_nil(2 <=> c)
assert_equal(Complex(SimpleRat(13,6),SimpleRat(5,2)), c + cc)
assert_equal(Complex(SimpleRat(-5,6),SimpleRat(-3,2)), c - cc)
......
r = c ** cc
assert_in_delta(0.1732, r.real, 0.001)
assert_in_delta(0.1186, r.imag, 0.001)
assert_raise(NoMethodError){c <=> cc}
assert_nil(c <=> cc)
assert_equal(Complex(SimpleRat(13,6),SimpleRat(5,2)), cc + c)
assert_equal(Complex(SimpleRat(5,6),SimpleRat(3,2)), cc - c)
......
r = cc ** c
assert_in_delta(0.5498, r.real, 0.001)
assert_in_delta(1.0198, r.imag, 0.001)
assert_raise(NoMethodError){cc <=> c}
assert_nil(cc <=> c)
assert_equal([SimpleRat,SimpleRat],
(+c).instance_eval{[real.class, imag.class]})
(1-1/3)