From 8f40b265811a23eef5b8c9e0b677b7d15cd6ea45 Mon Sep 17 00:00:00 2001 From: tadf Date: Fri, 22 Aug 2008 12:27:54 +0000 Subject: [PATCH] * complex.c (nucomp_div): now behaves as quo. * complex.c (nucomp_s_generic_p): has been removed. * complex.c (nucomp_to_s): adopts new form. * complex.c (nucomp_inspect): ditto. * complex.c (string_to_c_internal): ditto and supports polar form. * complex.c (rb_complex_polar): new. * rational.c (nurat_to_s): did not canonicalize. * rational.c (nurat_inspect): adopts new form. * rational.c (string_to_r_internal): ditto. * include/ruby/intern.h: added a declaration. * lib/complex.rb: added an obsolate class method. * lib/cmath.rb: use scalar? instead of generic?. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18778 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 26 +++ complex.c | 418 ++++++++++++++++--------------------- include/ruby/intern.h | 1 + lib/cmath.rb | 34 +-- lib/complex.rb | 6 + rational.c | 7 +- test/ruby/test_complex.rb | 97 +++++---- test/ruby/test_rational.rb | 47 +++-- 8 files changed, 327 insertions(+), 309 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2980450b5b..450130612f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +Fri Aug 22 21:18:40 2008 Tadayoshi Funaba + + * complex.c (nucomp_div): now behaves as quo. + + * complex.c (nucomp_s_generic_p): has been removed. + + * complex.c (nucomp_to_s): adopts new form. + + * complex.c (nucomp_inspect): ditto. + + * complex.c (string_to_c_internal): ditto and supports polar form. + + * complex.c (rb_complex_polar): new. + + * rational.c (nurat_to_s): did not canonicalize. + + * rational.c (nurat_inspect): adopts new form. + + * rational.c (string_to_r_internal): ditto. + + * include/ruby/intern.h: added a declaration. + + * lib/complex.rb: added an obsolate class method. + + * lib/cmath.rb: use scalar? instead of generic?. + Fri Aug 22 20:06:46 2008 Kazuhiro NISHIYAMA * lib/webrick/server.rb (WEBrick::GenericServer#shutdown): diff --git a/complex.c b/complex.c index 707383ac30..da8945ea9f 100644 --- a/complex.c +++ b/complex.c @@ -250,26 +250,6 @@ k_complex_p(VALUE x) return f_kind_of_p(x, rb_cComplex); } -inline static VALUE -f_generic_p(VALUE x) -{ - switch (TYPE(x)) { - case T_FIXNUM: - case T_BIGNUM: - case T_FLOAT: - case T_RATIONAL: - return Qtrue; - default: - return Qfalse; - } -} - -static VALUE -nucomp_s_generic_p(VALUE klass, VALUE x) -{ - return f_generic_p(x); -} - #define get_dat1(x) \ struct RComplex *dat;\ dat = ((struct RComplex *)(x)) @@ -322,12 +302,15 @@ nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass) inline static VALUE f_complex_new_bang1(VALUE klass, VALUE x) { + assert(!k_complex_p(x)); return nucomp_s_new_internal(klass, x, ZERO); } inline static VALUE f_complex_new_bang2(VALUE klass, VALUE x, VALUE y) { + assert(!k_complex_p(x)); + assert(!k_complex_p(y)); return nucomp_s_new_internal(klass, x, y); } @@ -343,7 +326,8 @@ nucomp_real_check(VALUE num) case T_RATIONAL: break; default: - rb_raise(rb_eArgError, "not a real"); + if (!k_numeric_p(num) || !f_scalar_p(num)) + rb_raise(rb_eArgError, "not a real"); } } @@ -459,7 +443,7 @@ extern VALUE math_sqrt(VALUE obj, VALUE x); static VALUE m_log_bang(VALUE x) { - return math_log(1, &x); + return math_log(1, &x); } #define m_sin_bang(x) math_sin(Qnil,x) @@ -471,7 +455,7 @@ m_cos(VALUE x) { get_dat1(x); - if (f_generic_p(x)) + if (f_scalar_p(x)) return m_cos_bang(x); return f_complex_new2(rb_cComplex, f_mul(m_cos_bang(dat->real), @@ -485,7 +469,7 @@ m_sin(VALUE x) { get_dat1(x); - if (f_generic_p(x)) + if (f_scalar_p(x)) return m_sin_bang(x); return f_complex_new2(rb_cComplex, f_mul(m_sin_bang(dat->real), @@ -497,7 +481,7 @@ m_sin(VALUE x) static VALUE m_sqrt(VALUE x) { - if (f_generic_p(x)) { + if (f_scalar_p(x)) { if (!f_negative_p(x)) return m_sqrt_bang(x); return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x))); @@ -516,12 +500,20 @@ m_sqrt(VALUE x) } } +inline static VALUE +f_complex_polar(VALUE klass, VALUE x, VALUE y) +{ + assert(!k_complex_p(x)); + assert(!k_complex_p(y)); + return nucomp_s_canonicalize_internal(klass, + f_mul(x, m_cos(y)), + f_mul(x, m_sin(y))); +} + static VALUE nucomp_s_polar(VALUE klass, VALUE abs, VALUE arg) { - return f_complex_new2(klass, - f_mul(abs, m_cos(arg)), - f_mul(abs, m_sin(arg))); + return f_complex_polar(klass, abs, arg); } static VALUE @@ -541,141 +533,104 @@ nucomp_image(VALUE self) static VALUE nucomp_add(VALUE self, VALUE other) { - switch (TYPE(other)) { - case T_FIXNUM: - case T_BIGNUM: - case T_FLOAT: - case T_RATIONAL: - { - get_dat1(self); + if (k_complex_p(other)) { + VALUE real, image; - return f_complex_new2(CLASS_OF(self), - f_add(dat->real, other), dat->image); - } - case T_COMPLEX: - { - VALUE real, image; + get_dat2(self, other); - get_dat2(self, other); + real = f_add(adat->real, bdat->real); + image = f_add(adat->image, bdat->image); - real = f_add(adat->real, bdat->real); - image = f_add(adat->image, bdat->image); - - return f_complex_new2(CLASS_OF(self), real, image); - } - default: - return rb_num_coerce_bin(self, other, '+'); + return f_complex_new2(CLASS_OF(self), real, image); } + if (k_numeric_p(other) && f_scalar_p(other)) { + get_dat1(self); + + return f_complex_new2(CLASS_OF(self), + f_add(dat->real, other), dat->image); + } + return rb_num_coerce_bin(self, other, '+'); } static VALUE nucomp_sub(VALUE self, VALUE other) { - switch (TYPE(other)) { - case T_FIXNUM: - case T_BIGNUM: - case T_FLOAT: - case T_RATIONAL: - { - get_dat1(self); + if (k_complex_p(other)) { + VALUE real, image; - return f_complex_new2(CLASS_OF(self), - f_sub(dat->real, other), dat->image); - } - case T_COMPLEX: - { - VALUE real, image; + get_dat2(self, other); - get_dat2(self, other); + real = f_sub(adat->real, bdat->real); + image = f_sub(adat->image, bdat->image); - real = f_sub(adat->real, bdat->real); - image = f_sub(adat->image, bdat->image); - - return f_complex_new2(CLASS_OF(self), real, image); - } - default: - return rb_num_coerce_bin(self, other, '-'); + return f_complex_new2(CLASS_OF(self), real, image); } + if (k_numeric_p(other) && f_scalar_p(other)) { + get_dat1(self); + + return f_complex_new2(CLASS_OF(self), + f_sub(dat->real, other), dat->image); + } + return rb_num_coerce_bin(self, other, '-'); } static VALUE nucomp_mul(VALUE self, VALUE other) { - switch (TYPE(other)) { - case T_FIXNUM: - case T_BIGNUM: - case T_FLOAT: - case T_RATIONAL: - { - get_dat1(self); + if (k_complex_p(other)) { + VALUE real, image; - return f_complex_new2(CLASS_OF(self), - f_mul(dat->real, other), - f_mul(dat->image, other)); - } - case T_COMPLEX: - { - VALUE real, image; + get_dat2(self, other); - get_dat2(self, other); + real = f_sub(f_mul(adat->real, bdat->real), + f_mul(adat->image, bdat->image)); + image = f_add(f_mul(adat->real, bdat->image), + f_mul(adat->image, bdat->real)); - real = f_sub(f_mul(adat->real, bdat->real), - f_mul(adat->image, bdat->image)); - image = f_add(f_mul(adat->real, bdat->image), - f_mul(adat->image, bdat->real)); - - return f_complex_new2(CLASS_OF(self), real, image); - } - default: - return rb_num_coerce_bin(self, other, '*'); + return f_complex_new2(CLASS_OF(self), real, image); } + if (k_numeric_p(other) && f_scalar_p(other)) { + get_dat1(self); + + return f_complex_new2(CLASS_OF(self), + f_mul(dat->real, other), + f_mul(dat->image, other)); + } + return rb_num_coerce_bin(self, other, '*'); } +#define f_div f_quo + static VALUE nucomp_div(VALUE self, VALUE other) { - switch (TYPE(other)) { - case T_FIXNUM: - case T_BIGNUM: - case T_FLOAT: - case T_RATIONAL: - { - get_dat1(self); + if (k_complex_p(other)) { + get_dat2(self, other); - return f_complex_new2(CLASS_OF(self), - f_div(dat->real, other), - f_div(dat->image, other)); + if (TYPE(adat->real) == T_FLOAT || + TYPE(adat->image) == T_FLOAT || + TYPE(bdat->real) == T_FLOAT || + TYPE(bdat->image) == T_FLOAT) { + VALUE magn = m_hypot(bdat->real, bdat->image); + VALUE tmp = f_complex_new_bang2(CLASS_OF(self), + f_div(bdat->real, magn), + f_div(bdat->image, magn)); + return f_div(f_mul(self, f_conjugate(tmp)), magn); } - case T_COMPLEX: - { - get_dat2(self, other); - - if (TYPE(adat->real) == T_FLOAT || - TYPE(adat->image) == T_FLOAT || - TYPE(bdat->real) == T_FLOAT || - TYPE(bdat->image) == T_FLOAT) { - VALUE magn = m_hypot(bdat->real, bdat->image); - VALUE tmp = f_complex_new_bang2(CLASS_OF(self), - f_div(bdat->real, magn), - f_div(bdat->image, magn)); - return f_div(f_mul(self, f_conjugate(tmp)), magn); - } - return f_div(f_mul(self, f_conjugate(other)), f_abs2(other)); - } - default: - return rb_num_coerce_bin(self, other, '/'); + return f_div(f_mul(self, f_conjugate(other)), f_abs2(other)); } + if (k_numeric_p(other) && f_scalar_p(other)) { + get_dat1(self); + + return f_complex_new2(CLASS_OF(self), + f_div(dat->real, other), + f_div(dat->image, other)); + } + return rb_num_coerce_bin(self, other, '/'); } -static VALUE -nucomp_quo(VALUE self, VALUE other) -{ - get_dat1(self); - - return f_div(f_complex_new2(CLASS_OF(self), - f_quo(dat->real, ONE), - f_quo(dat->image, ONE)), other); -} +#undef f_div +#define nucomp_quo nucomp_div static VALUE nucomp_fdiv(VALUE self, VALUE other) @@ -696,9 +651,23 @@ nucomp_expt(VALUE self, VALUE other) if (k_rational_p(other) && f_one_p(f_denominator(other))) other = f_numerator(other); /* good? */ - switch (TYPE(other)) { - case T_FIXNUM: - case T_BIGNUM: + if (k_complex_p(other)) { + VALUE a, r, theta, ore, oim, nr, ntheta; + + get_dat1(other); + + a = f_polar(self); + r = RARRAY_PTR(a)[0]; + theta = RARRAY_PTR(a)[1]; + + ore = dat->real; + oim = dat->image; + nr = m_exp_bang(f_sub(f_mul(ore, m_log_bang(r)), + f_mul(oim, theta))); + ntheta = f_add(f_mul(theta, ore), f_mul(oim, m_log_bang(r))); + return f_complex_polar(CLASS_OF(self), nr, ntheta); + } + if (k_integer_p(other)) { if (f_gt_p(other, ZERO)) { VALUE x, z, n; @@ -725,74 +694,41 @@ nucomp_expt(VALUE self, VALUE other) return z; } return f_expt(f_div(f_to_r(ONE), self), f_negate(other)); - case T_FLOAT: - case T_RATIONAL: - { - VALUE a, r, theta; - - a = f_polar(self); - r = RARRAY_PTR(a)[0]; - theta = RARRAY_PTR(a)[1]; - return nucomp_s_polar(CLASS_OF(self), f_expt(r, other), - f_mul(theta, other)); - } - case T_COMPLEX: - { - VALUE a, r, theta, ore, oim, nr, ntheta; - - get_dat1(other); - - a = f_polar(self); - r = RARRAY_PTR(a)[0]; - theta = RARRAY_PTR(a)[1]; - - ore = dat->real; - oim = dat->image; - nr = m_exp_bang(f_sub(f_mul(ore, m_log_bang(r)), - f_mul(oim, theta))); - ntheta = f_add(f_mul(theta, ore), f_mul(oim, m_log_bang(r))); - return nucomp_s_polar(CLASS_OF(self), nr, ntheta); - } - default: - return rb_num_coerce_bin(self, other, id_expt); } + if (k_numeric_p(other) && f_scalar_p(other)) { + VALUE a, r, theta; + + a = f_polar(self); + r = RARRAY_PTR(a)[0]; + theta = RARRAY_PTR(a)[1]; + return f_complex_polar(CLASS_OF(self), f_expt(r, other), + f_mul(theta, other)); + } + return rb_num_coerce_bin(self, other, id_expt); } static VALUE nucomp_equal_p(VALUE self, VALUE other) { - switch (TYPE(other)) { - case T_FIXNUM: - case T_BIGNUM: - case T_FLOAT: - case T_RATIONAL: - { - get_dat1(self); + if (k_complex_p(other)) { + get_dat2(self, other); - return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->image)); - } - case T_COMPLEX: - { - get_dat2(self, other); - - return f_boolcast(f_equal_p(adat->real, bdat->real) && - f_equal_p(adat->image, bdat->image)); - } - default: - return f_equal_p(other, self); + return f_boolcast(f_equal_p(adat->real, bdat->real) && + f_equal_p(adat->image, bdat->image)); } + if (k_numeric_p(other) && f_scalar_p(other)) { + get_dat1(self); + + return f_boolcast(f_equal_p(dat->real, other) && f_zero_p(dat->image)); + } + return f_equal_p(other, self); } static VALUE nucomp_coerce(VALUE self, VALUE other) { - switch (TYPE(other)) { - case T_FIXNUM: - case T_BIGNUM: - case T_FLOAT: - case T_RATIONAL: + if (k_numeric_p(other) && f_scalar_p(other)) return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self); - } rb_raise(rb_eTypeError, "%s can't be coerced into %s", rb_obj_classname(other), rb_obj_classname(self)); @@ -918,12 +854,6 @@ f_signbit(VALUE x) return f_negative_p(x); } -inline static VALUE -f_tzero_p(VALUE x) -{ - return f_boolcast(f_zero_p(x) && !f_signbit(x)); -} - inline static VALUE f_tpositive_p(VALUE x) { @@ -933,30 +863,17 @@ f_tpositive_p(VALUE x) static VALUE nucomp_to_s(VALUE self) { - VALUE s, rezero, impos; + VALUE s, impos; get_dat1(self); - rezero = f_tzero_p(dat->real); impos = f_tpositive_p(dat->image); - if (rezero) - s = rb_str_new2(""); - else { - s = f_to_s(dat->real); - rb_str_cat2(s, !impos ? "-" : "+"); - } + s = f_to_s(dat->real); + rb_str_cat2(s, !impos ? "-" : "+"); - if (k_rational_p(dat->image) && - !f_one_p(f_denominator(dat->image))) { - rb_str_cat2(s, "("); - rb_str_concat(s, f_to_s(rezero ? dat->image : f_abs(dat->image))); - rb_str_cat2(s, ")i"); - } - else { - rb_str_concat(s, f_to_s(rezero ? dat->image : f_abs(dat->image))); - rb_str_cat2(s, "i"); - } + rb_str_concat(s, f_to_s(f_abs(dat->image))); + rb_str_cat2(s, "i"); return s; } @@ -964,15 +881,18 @@ nucomp_to_s(VALUE self) static VALUE nucomp_inspect(VALUE self) { - VALUE s; + VALUE s, impos; get_dat1(self); - s = rb_str_new2("Complex("); + impos = f_tpositive_p(dat->image); + + s = rb_str_new2("("); rb_str_concat(s, f_inspect(dat->real)); - rb_str_cat2(s, ", "); - rb_str_concat(s, f_inspect(dat->image)); - rb_str_cat2(s, ")"); + rb_str_cat2(s, !impos ? "-" : "+"); + + rb_str_concat(s, f_inspect(f_abs(dat->image))); + rb_str_cat2(s, "i)"); return s; } @@ -1007,6 +927,12 @@ rb_complex_new(VALUE x, VALUE y) return nucomp_s_canonicalize_internal(rb_cComplex, x, y); } +VALUE +rb_complex_polar(VALUE x, VALUE y) +{ + return nucomp_s_polar(rb_cComplex, x, y); +} + static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass); VALUE @@ -1075,25 +1001,30 @@ numeric_to_c(VALUE self) return rb_complex_new1(self); } -static VALUE comp_pat1, comp_pat2, a_slash, a_dot_and_an_e, +static VALUE comp_pat0, comp_pat1, comp_pat2, a_slash, a_dot_and_an_e, null_string, underscores_pat, an_underscore; #define DIGITS "(?:\\d(?:_\\d|\\d)*)" #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?" -#define DENOMINATOR "[-+]?" DIGITS +#define DENOMINATOR DIGITS #define NUMBER "[-+]?" NUMERATOR "(?:\\/" DENOMINATOR ")?" #define NUMBERNOS NUMERATOR "(?:\\/" DENOMINATOR ")?" -#define PATTERN1 "\\A((" NUMBER ")|\\((" NUMBER ")\\))?[iIjJ]" -#define PATTERN2 "\\A(" NUMBER ")(([-+])(?:(" NUMBERNOS ")|\\((" NUMBER ")\\))?[iIjJ])?" +#define PATTERN0 "\\A(" NUMBER ")@(" NUMBER ")" +#define PATTERN1 "\\A([-+])?(" NUMBER ")?[iIjJ]" +#define PATTERN2 "\\A(" NUMBER ")(([-+])(" NUMBERNOS ")?[iIjJ])?" static void make_patterns(void) { + static const char comp_pat0_source[] = PATTERN0; static const char comp_pat1_source[] = PATTERN1; static const char comp_pat2_source[] = PATTERN2; static const char underscores_pat_source[] = "_+"; - if (comp_pat1) return; + if (comp_pat0) return; + + comp_pat0 = rb_reg_new(comp_pat0_source, sizeof comp_pat0_source - 1, 0); + rb_global_variable(&comp_pat0); comp_pat1 = rb_reg_new(comp_pat1_source, sizeof comp_pat1_source - 1, 0); rb_global_variable(&comp_pat1); @@ -1154,19 +1085,33 @@ string_to_c_internal(VALUE self) { VALUE m, sr, si, re, r, i; + int po; - m = f_match(comp_pat1, s); + m = f_match(comp_pat0, s); if (!NIL_P(m)) { - sr = Qnil; - si = f_aref(m, INT2FIX(1)); - if (NIL_P(si)) - si = rb_str_new2("1"); - else { - si = f_aref(m, INT2FIX(2)); + sr = f_aref(m, INT2FIX(1)); + si = f_aref(m, INT2FIX(2)); + re = f_post_match(m); + po = 1; + } + if (NIL_P(m)) { + m = f_match(comp_pat1, s); + if (!NIL_P(m)) { + sr = Qnil; + si = f_aref(m, INT2FIX(1)); if (NIL_P(si)) - si = f_aref(m, INT2FIX(3)); + si = rb_str_new2(""); + { + VALUE t; + + t = f_aref(m, INT2FIX(2)); + if (NIL_P(t)) + t = rb_str_new2("1"); + rb_str_concat(si, t); + } + re = f_post_match(m); + po = 0; } - re = f_post_match(m); } if (NIL_P(m)) { m = f_match(comp_pat2, s); @@ -1181,13 +1126,12 @@ string_to_c_internal(VALUE self) si = f_aref(m, INT2FIX(3)); t = f_aref(m, INT2FIX(4)); - if (NIL_P(t)) - t = f_aref(m, INT2FIX(5)); if (NIL_P(t)) t = rb_str_new2("1"); rb_str_concat(si, t); } re = f_post_match(m); + po = 0; } r = INT2FIX(0); i = INT2FIX(0); @@ -1207,7 +1151,11 @@ string_to_c_internal(VALUE self) else i = f_to_i(si); } - return rb_assoc_new(rb_complex_new2(r, i), re); + if (po) + return rb_assoc_new(rb_complex_polar(r, i), re); + else + return rb_assoc_new(rb_complex_new2(r, i), re); + } } @@ -1410,8 +1358,6 @@ Init_Complex(void) rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("allocate"))); - rb_define_singleton_method(rb_cComplex, "generic?", nucomp_s_generic_p, 1); - rb_define_singleton_method(rb_cComplex, "new!", nucomp_s_new_bang, -1); rb_funcall(rb_cComplex, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("new!"))); diff --git a/include/ruby/intern.h b/include/ruby/intern.h index eed85edc3c..a75f813d12 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -135,6 +135,7 @@ VALUE rb_complex_raw(VALUE, VALUE); VALUE rb_complex_new(VALUE, VALUE); #define rb_complex_new1(x) rb_complex_new(x, INT2FIX(0)) #define rb_complex_new2(x,y) rb_complex_new(x, y) +VALUE rb_complex_polar(VALUE, VALUE); VALUE rb_Complex(VALUE, VALUE); #define rb_Complex1(x) rb_Complex(x, INT2FIX(0)) #define rb_Complex2(x,y) rb_Complex(x, y) diff --git a/lib/cmath.rb b/lib/cmath.rb index 158da4175d..55995879e6 100644 --- a/lib/cmath.rb +++ b/lib/cmath.rb @@ -25,7 +25,7 @@ module CMath alias atanh! atanh def exp(z) - if Complex.generic?(z) + if z.scalar? exp!(z) else Complex(exp!(z.real) * cos!(z.image), @@ -35,7 +35,7 @@ module CMath def log(*args) z, b = args - if Complex.generic?(z) and z >= 0 and (b.nil? or b >= 0) + if z.scalar? and z >= 0 and (b.nil? or b >= 0) log!(*args) else r, theta = z.polar @@ -48,7 +48,7 @@ module CMath end def log10(z) - if Complex.generic?(z) + if z.scalar? log10!(z) else log(z) / log!(10) @@ -56,7 +56,7 @@ module CMath end def sqrt(z) - if Complex.generic?(z) + if z.scalar? if z >= 0 sqrt!(z) else @@ -74,7 +74,7 @@ module CMath end def sin(z) - if Complex.generic?(z) + if z.scalar? sin!(z) else Complex(sin!(z.real) * cosh!(z.image), @@ -83,7 +83,7 @@ module CMath end def cos(z) - if Complex.generic?(z) + if z.scalar? cos!(z) else Complex(cos!(z.real) * cosh!(z.image), @@ -92,7 +92,7 @@ module CMath end def tan(z) - if Complex.generic?(z) + if z.scalar? tan!(z) else sin(z)/cos(z) @@ -100,7 +100,7 @@ module CMath end def sinh(z) - if Complex.generic?(z) + if z.scalar? sinh!(z) else Complex(sinh!(z.real) * cos!(z.image), @@ -109,7 +109,7 @@ module CMath end def cosh(z) - if Complex.generic?(z) + if z.scalar? cosh!(z) else Complex(cosh!(z.real) * cos!(z.image), @@ -118,7 +118,7 @@ module CMath end def tanh(z) - if Complex.generic?(z) + if z.scalar? tanh!(z) else sinh(z) / cosh(z) @@ -126,7 +126,7 @@ module CMath end def asin(z) - if Complex.generic?(z) and z >= -1 and z <= 1 + if z.scalar? and z >= -1 and z <= 1 asin!(z) else -1.0.im * log(1.0.im * z + sqrt(1.0 - z * z)) @@ -134,7 +134,7 @@ module CMath end def acos(z) - if Complex.generic?(z) and z >= -1 and z <= 1 + if z.scalar? and z >= -1 and z <= 1 acos!(z) else -1.0.im * log(z + 1.0.im * sqrt(1.0 - z * z)) @@ -142,7 +142,7 @@ module CMath end def atan(z) - if Complex.generic?(z) + if z.scalar? atan!(z) else 1.0.im * log((1.0.im + z) / (1.0.im - z)) / 2.0 @@ -150,7 +150,7 @@ module CMath end def atan2(y,x) - if Complex.generic?(y) and Complex.generic?(x) + if y.scalar? and x.scalar? atan2!(y,x) else -1.0.im * log((x + 1.0.im * y) / sqrt(x * x + y * y)) @@ -158,7 +158,7 @@ module CMath end def acosh(z) - if Complex.generic?(z) and z >= 1 + if z.scalar? and z >= 1 acosh!(z) else log(z + sqrt(z * z - 1.0)) @@ -166,7 +166,7 @@ module CMath end def asinh(z) - if Complex.generic?(z) + if z.scalar? asinh!(z) else log(z + sqrt(1.0 + z * z)) @@ -174,7 +174,7 @@ module CMath end def atanh(z) - if Complex.generic?(z) and z >= -1 and z <= 1 + if z.scalar? and z >= -1 and z <= 1 atanh!(z) else log((1.0 + z) / (1.0 - z)) / 2.0 diff --git a/lib/complex.rb b/lib/complex.rb index 0e88dd5f4f..1845f30b1f 100644 --- a/lib/complex.rb +++ b/lib/complex.rb @@ -2,3 +2,9 @@ require 'cmath' Object.instance_eval{remove_const :Math} Math = CMath + +def Complex.generic? (other) + other.kind_of?(Integer) || + other.kind_of?(Float) || + other.kind_of?(Rational) +end diff --git a/rational.c b/rational.c index 19bb037be1..1a0f4cbabc 100644 --- a/rational.c +++ b/rational.c @@ -1117,9 +1117,6 @@ static VALUE nurat_to_s(VALUE self) { get_dat1(self); - - if (f_one_p(dat->den)) - return f_to_s(dat->num); return rb_funcall(rb_mKernel, id_format, 3, rb_str_new2("%d/%d"), dat->num, dat->den); } @@ -1129,7 +1126,7 @@ nurat_inspect(VALUE self) { get_dat1(self); return rb_funcall(rb_mKernel, id_format, 3, - rb_str_new2("Rational(%d, %d)"), dat->num, dat->den); + rb_str_new2("(%d/%d)"), dat->num, dat->den); } static VALUE @@ -1234,7 +1231,7 @@ static VALUE rat_pat, an_e_pat, a_dot_pat, underscores_pat, an_underscore; #define DIGITS "(?:\\d(?:_\\d|\\d)*)" #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?" -#define DENOMINATOR "[-+]?" DIGITS +#define DENOMINATOR DIGITS #define PATTERN "\\A([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?" static void diff --git a/test/ruby/test_complex.rb b/test/ruby/test_complex.rb index f2324a2b72..b661864519 100644 --- a/test/ruby/test_complex.rb +++ b/test/ruby/test_complex.rb @@ -349,10 +349,12 @@ class Complex_Test < Test::Unit::TestCase c = Complex(1,2) c2 = Complex(2,3) - if defined?(Complex::Unify) + if defined?(Rational) assert_equal(Complex(Rational(8,13),Rational(1,13)), c / c2) else - assert_equal(Complex(0,0), c / c2) + r = c / c2 + assert_in_delta(0.615, r.real, 0.001) + assert_in_delta(0.076, r.image, 0.001) end c = Complex(1.0,2.0) @@ -365,10 +367,10 @@ class Complex_Test < Test::Unit::TestCase c = Complex(1,2) c2 = Complex(2,3) - if defined?(Complex::Unify) + if defined?(Rational) assert_equal(Complex(Rational(1,2),1), c / 2) else - assert_equal(Complex(0,1), c / 2) + assert_equal(Complex(0.5,1.0), c / 2) end assert_equal(Complex(0.5,1.0), c / 2.0) @@ -533,38 +535,38 @@ class Complex_Test < Test::Unit::TestCase assert_instance_of(String, c.to_s) assert_equal('1+2i', c.to_s) - assert_equal('2i', Complex(0,2).to_s) - assert_equal('-2i', Complex(0,-2).to_s) + assert_equal('0+2i', Complex(0,2).to_s) + assert_equal('0-2i', Complex(0,-2).to_s) assert_equal('1+2i', Complex(1,2).to_s) assert_equal('-1+2i', Complex(-1,2).to_s) assert_equal('-1-2i', Complex(-1,-2).to_s) assert_equal('1-2i', Complex(1,-2).to_s) assert_equal('-1-2i', Complex(-1,-2).to_s) - assert_equal('2.0i', Complex(0,2.0).to_s) - assert_equal('-2.0i', Complex(0,-2.0).to_s) + assert_equal('0+2.0i', Complex(0,2.0).to_s) + assert_equal('0-2.0i', Complex(0,-2.0).to_s) assert_equal('1.0+2.0i', Complex(1.0,2.0).to_s) assert_equal('-1.0+2.0i', Complex(-1.0,2.0).to_s) assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s) assert_equal('1.0-2.0i', Complex(1.0,-2.0).to_s) assert_equal('-1.0-2.0i', Complex(-1.0,-2.0).to_s) - if defined?(Rational) - assert_equal('2i', Complex(0,Rational(2)).to_s) - assert_equal('-2i', Complex(0,Rational(-2)).to_s) - assert_equal('1+2i', Complex(1,Rational(2)).to_s) - assert_equal('-1+2i', Complex(-1,Rational(2)).to_s) - assert_equal('-1-2i', Complex(-1,Rational(-2)).to_s) - assert_equal('1-2i', Complex(1,Rational(-2)).to_s) - assert_equal('-1-2i', Complex(-1,Rational(-2)).to_s) + if defined?(Rational) && !defined?(Complex::Unify) && !Rational.instance_variable_get('@RCS_ID') + assert_equal('0+2/1i', Complex(0,Rational(2)).to_s) + assert_equal('0-2/1i', Complex(0,Rational(-2)).to_s) + assert_equal('1+2/1i', Complex(1,Rational(2)).to_s) + assert_equal('-1+2/1i', Complex(-1,Rational(2)).to_s) + assert_equal('-1-2/1i', Complex(-1,Rational(-2)).to_s) + assert_equal('1-2/1i', Complex(1,Rational(-2)).to_s) + assert_equal('-1-2/1i', Complex(-1,Rational(-2)).to_s) - assert_equal('(2/3)i', Complex(0,Rational(2,3)).to_s) - assert_equal('(-2/3)i', Complex(0,Rational(-2,3)).to_s) - assert_equal('1+(2/3)i', Complex(1,Rational(2,3)).to_s) - assert_equal('-1+(2/3)i', Complex(-1,Rational(2,3)).to_s) - assert_equal('-1-(2/3)i', Complex(-1,Rational(-2,3)).to_s) - assert_equal('1-(2/3)i', Complex(1,Rational(-2,3)).to_s) - assert_equal('-1-(2/3)i', Complex(-1,Rational(-2,3)).to_s) + assert_equal('0+2/3i', Complex(0,Rational(2,3)).to_s) + assert_equal('0-2/3i', Complex(0,Rational(-2,3)).to_s) + assert_equal('1+2/3i', Complex(1,Rational(2,3)).to_s) + assert_equal('-1+2/3i', Complex(-1,Rational(2,3)).to_s) + assert_equal('-1-2/3i', Complex(-1,Rational(-2,3)).to_s) + assert_equal('1-2/3i', Complex(1,Rational(-2,3)).to_s) + assert_equal('-1-2/3i', Complex(-1,Rational(-2,3)).to_s) end end @@ -572,7 +574,7 @@ class Complex_Test < Test::Unit::TestCase c = Complex(1,2) assert_instance_of(String, c.inspect) - assert_equal('Complex(1, 2)', c.inspect) + assert_equal('(1+2i)', c.inspect) end def test_marshal @@ -604,6 +606,10 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(-5,-3), '-5-3i'.to_c) assert_equal(Complex(0,3), '3i'.to_c) assert_equal(Complex(0,-3), '-3i'.to_c) + assert_equal(Complex(5,1), '5+i'.to_c) + assert_equal(Complex(0,1), 'i'.to_c) + assert_equal(Complex(0,1), '+i'.to_c) + assert_equal(Complex(0,-1), '-i'.to_c) assert_equal(Complex(5,3), '5+3I'.to_c) assert_equal(Complex(5,3), '5+3j'.to_c) @@ -611,6 +617,8 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(0,3), '3I'.to_c) assert_equal(Complex(0,3), '3j'.to_c) assert_equal(Complex(0,3), '3J'.to_c) + assert_equal(Complex(0,1), 'I'.to_c) + assert_equal(Complex(0,1), 'J'.to_c) assert_equal(Complex(5.0), '5.0'.to_c) assert_equal(Complex(-5.0), '-5.0'.to_c) @@ -630,6 +638,11 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(0.0,3.0), '3e0i'.to_c) assert_equal(Complex(0.0,-3.0), '-3e0i'.to_c) + assert_equal(Complex.polar(10,10), '10@10'.to_c) + assert_equal(Complex.polar(-10,-10), '-10@-10'.to_c) + assert_equal(Complex.polar(10.5,10.5), '10.5@10.5'.to_c) + assert_equal(Complex.polar(-10.5,-10.5), '-10.5@-10.5'.to_c) + assert_equal(Complex(5), Complex('5')) assert_equal(Complex(-5), Complex('-5')) assert_equal(Complex(5,3), Complex('5+3i')) @@ -638,6 +651,10 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(-5,-3), Complex('-5-3i')) assert_equal(Complex(0,3), Complex('3i')) assert_equal(Complex(0,-3), Complex('-3i')) + assert_equal(Complex(5,1), Complex('5+i')) + assert_equal(Complex(0,1), Complex('i')) + assert_equal(Complex(0,1), Complex('+i')) + assert_equal(Complex(0,-1), Complex('-i')) assert_equal(Complex(5,3), Complex('5+3I')) assert_equal(Complex(5,3), Complex('5+3j')) @@ -645,6 +662,8 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(0,3), Complex('3I')) assert_equal(Complex(0,3), Complex('3j')) assert_equal(Complex(0,3), Complex('3J')) + assert_equal(Complex(0,1), Complex('I')) + assert_equal(Complex(0,1), Complex('J')) assert_equal(Complex(5.0), Complex('5.0')) assert_equal(Complex(-5.0), Complex('-5.0')) @@ -664,6 +683,11 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(0.0,3.0), Complex('3e0i')) assert_equal(Complex(0.0,-3.0), Complex('-3e0i')) + assert_equal(Complex.polar(10,10), Complex('10@10')) + assert_equal(Complex.polar(-10,-10), Complex('-10@-10')) + assert_equal(Complex.polar(10.5,10.5), Complex('10.5@10.5')) + assert_equal(Complex.polar(-10.5,-10.5), Complex('-10.5@-10.5')) + assert_equal(Complex(0), '_'.to_c) assert_equal(Complex(0), '_5'.to_c) assert_equal(Complex(5), '5_'.to_c) @@ -693,13 +717,14 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-3/2i'.to_c) assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+3/2i'.to_c) assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-3/2i'.to_c) - assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+(3/2)i'.to_c) - assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-(3/2)i'.to_c) - assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+(3/2)i'.to_c) - assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-(3/2)i'.to_c) + assert_equal(Complex(Rational(1,5),Rational(3,2)), '1/5+3/2i'.to_c) + assert_equal(Complex(Rational(1,5),Rational(-3,2)), '1/5-3/2i'.to_c) + assert_equal(Complex(Rational(-1,5),Rational(3,2)), '-1/5+3/2i'.to_c) + assert_equal(Complex(Rational(-1,5),Rational(-3,2)), '-1/5-3/2i'.to_c) + assert_equal(Complex.polar(Rational(1,5),Rational(3,2)), Complex('1/5@3/2')) + assert_equal(Complex.polar(Rational(-1,5),Rational(-3,2)), Complex('-1/5@-3/2')) end - assert_equal(Complex(5, 3), Complex('5', '3')) end def test_respond @@ -855,13 +880,15 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(0.5,1.0), Complex(1,2).quo(2)) end +=begin if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID') - assert_equal(Rational(1,2), 1.quo(2)) - assert_equal(Rational(5000000000), 10000000000.quo(2)) - assert_equal(Rational(1,2), 1.0.quo(2)) - assert_equal(Rational(1,4), Rational(1,2).quo(2)) + assert_equal(Rational(1,2), 1.rdiv(2)) + assert_equal(Rational(5000000000), 10000000000.rdiv(2)) + assert_equal(Rational(1,2), 1.0.rdiv(2)) + assert_equal(Rational(1,4), Rational(1,2).rdiv(2)) assert_equal(Complex(Rational(1,2),Rational(1)), Complex(1,2).quo(2)) end +=end assert_equal(0.5, 1.fdiv(2)) assert_equal(5000000000.0, 10000000000.fdiv(2)) @@ -981,6 +1008,7 @@ class Complex_Test < Test::Unit::TestCase end +=begin def test_canonicalize f = defined?(Complex::Unify) Complex.const_set(:Unify, true) unless f @@ -1055,7 +1083,6 @@ class Complex_Test < Test::Unit::TestCase Complex.const_set(:Unify, unify_val) if f end -=begin def test_abs b = 2**100 def b.*(x); self; end rescue nil @@ -1076,7 +1103,6 @@ class Complex_Test < Test::Unit::TestCase nan = inf/inf assert_raise(Errno::EDOM, Errno::ERANGE) { Complex(1, nan).abs } end -=end def test_coerce c = Complex(6, 3) @@ -1106,6 +1132,7 @@ class Complex_Test < Test::Unit::TestCase assert_equal(Complex(0, -1), Complex(0, 1) ** (2**100-1)) assert_equal(Complex(1, 0), Complex(1, 0) ** Rational(1, 2**100)) end +=end def test_fixed_bug if defined?(Rational) && !Rational.instance_variable_get('@RCS_ID') diff --git a/test/ruby/test_rational.rb b/test/ruby/test_rational.rb index 0a72fa12ad..eb52e3e193 100644 --- a/test/ruby/test_rational.rb +++ b/test/ruby/test_rational.rb @@ -83,6 +83,8 @@ class Rational_Test < Test::Unit::TestCase instance_eval{[numerator, denominator]}) assert_equal([0,1], Rational.__send__(:new!, nil). instance_eval{[numerator, denominator]}) + + assert_raise(ZeroDivisionError){Rational.__send__(:new!, 1, 0)} end =begin @@ -621,6 +623,10 @@ class Rational_Test < Test::Unit::TestCase assert_instance_of(Rational, x) assert_equal(1, x.numerator) assert_equal(4, x.denominator) + + unless defined?(Rational::Unify) # maybe bug mathn + assert_raise(ZeroDivisionError){0 ** -1} + end end def test_cmp @@ -676,8 +682,6 @@ class Rational_Test < Test::Unit::TestCase assert_equal(true, Rational(2,1) != Rational(1)) assert_equal(false, Rational(1) == nil) assert_equal(false, Rational(1) == '') - - assert_equal(false, Rational(1,2**100) == 1) end def test_unify @@ -698,8 +702,13 @@ class Rational_Test < Test::Unit::TestCase assert_instance_of(String, c.to_s) assert_equal('1/2', c.to_s) - assert_equal('0', Rational(0,2).to_s) - assert_equal('0', Rational(0,-2).to_s) + if defined?(Rational::Unify) + assert_equal('0', Rational(0,2).to_s) + assert_equal('0', Rational(0,-2).to_s) + else + assert_equal('0/1', Rational(0,2).to_s) + assert_equal('0/1', Rational(0,-2).to_s) + end assert_equal('1/2', Rational(1,2).to_s) assert_equal('-1/2', Rational(-1,2).to_s) assert_equal('1/2', Rational(-1,-2).to_s) @@ -711,7 +720,7 @@ class Rational_Test < Test::Unit::TestCase c = Rational(1,2) assert_instance_of(String, c.inspect) - assert_equal('Rational(1, 2)', c.inspect) + assert_equal('(1/2)', c.inspect) end def test_marshal @@ -721,6 +730,10 @@ class Rational_Test < Test::Unit::TestCase c2 = Marshal.load(s) assert_equal(c, c2) assert_instance_of(Rational, c2) + + assert_raise(ZeroDivisionError){ + Marshal.load("\x04\bU:\rRational[\ai\x06i\x05") + } end def test_parse @@ -730,22 +743,22 @@ class Rational_Test < Test::Unit::TestCase assert_equal(Rational(-5), '-5'.to_r) assert_equal(Rational(5,3), '5/3'.to_r) assert_equal(Rational(-5,3), '-5/3'.to_r) - assert_equal(Rational(5,-3), '5/-3'.to_r) - assert_equal(Rational(-5,-3), '-5/-3'.to_r) +# assert_equal(Rational(5,-3), '5/-3'.to_r) +# assert_equal(Rational(-5,-3), '-5/-3'.to_r) assert_equal(Rational(5), '5.0'.to_r) assert_equal(Rational(-5), '-5.0'.to_r) assert_equal(Rational(5,3), '5.0/3'.to_r) assert_equal(Rational(-5,3), '-5.0/3'.to_r) - assert_equal(Rational(5,-3), '5.0/-3'.to_r) - assert_equal(Rational(-5,-3), '-5.0/-3'.to_r) +# assert_equal(Rational(5,-3), '5.0/-3'.to_r) +# assert_equal(Rational(-5,-3), '-5.0/-3'.to_r) assert_equal(Rational(5), '5e0'.to_r) assert_equal(Rational(-5), '-5e0'.to_r) assert_equal(Rational(5,3), '5e0/3'.to_r) assert_equal(Rational(-5,3), '-5e0/3'.to_r) - assert_equal(Rational(5,-3), '5e0/-3'.to_r) - assert_equal(Rational(-5,-3), '-5e0/-3'.to_r) +# assert_equal(Rational(5,-3), '5e0/-3'.to_r) +# assert_equal(Rational(-5,-3), '-5e0/-3'.to_r) assert_equal(Rational(33,100), '0.33'.to_r) assert_equal(Rational(-33,100), '-0.33'.to_r) @@ -765,8 +778,8 @@ class Rational_Test < Test::Unit::TestCase assert_equal(Rational(-5), Rational('-5')) assert_equal(Rational(5,3), Rational('5/3')) assert_equal(Rational(-5,3), Rational('-5/3')) - assert_equal(Rational(5,-3), Rational('5/-3')) - assert_equal(Rational(-5,-3), Rational('-5/-3')) +# assert_equal(Rational(5,-3), Rational('5/-3')) +# assert_equal(Rational(-5,-3), Rational('-5/-3')) assert_equal(Rational(33,100), Rational('0.33')) assert_equal(Rational(-33,100), Rational('-0.33')) @@ -783,8 +796,8 @@ class Rational_Test < Test::Unit::TestCase assert_equal(Rational(-5.0), Rational('-5.0')) assert_equal(Rational(5.0,3), Rational('5.0/3')) assert_equal(Rational(-5.0,3), Rational('-5.0/3')) - assert_equal(Rational(5.0,-3), Rational('5.0/-3')) - assert_equal(Rational(-5.0,-3), Rational('-5.0/-3')) +# assert_equal(Rational(5.0,-3), Rational('5.0/-3')) +# assert_equal(Rational(-5.0,-3), Rational('-5.0/-3')) assert_equal(Rational(0), '_'.to_r) assert_equal(Rational(0), '_5'.to_r) @@ -933,7 +946,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(Rational(1,2), 1.quo(2)) assert_equal(Rational(5000000000), 10000000000.quo(2)) - assert_equal(Rational(1,2), 1.0.quo(2)) + assert_equal(0.5, 1.0.quo(2)) assert_equal(Rational(1,4), Rational(1,2).quo(2)) assert_equal(0.5, 1.fdiv(2)) @@ -942,6 +955,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(0.25, Rational(1,2).fdiv(2)) end +=begin def test_zero_div assert_raise(ZeroDivisionError) { Rational(1, 0) } assert_raise(ZeroDivisionError) { Rational(1, 1) / 0 } @@ -1043,6 +1057,7 @@ class Rational_Test < Test::Unit::TestCase assert_equal(1, Rational(2**5000,3).to_f.infinite?) assert_equal(0, Rational(1, 2**5000).to_f) end +=end def test_fixed_bug if defined?(Rational::Unify)