diff options
Diffstat (limited to 'complex.c')
| -rw-r--r-- | complex.c | 593 |
1 files changed, 386 insertions, 207 deletions
@@ -20,6 +20,7 @@ #include "internal/array.h" #include "internal/class.h" #include "internal/complex.h" +#include "internal/error.h" #include "internal/math.h" #include "internal/numeric.h" #include "internal/object.h" @@ -51,20 +52,6 @@ static ID id_abs, id_arg, #define id_quo idQuo #define id_fdiv idFdiv -#define fun1(n) \ -inline static VALUE \ -f_##n(VALUE x)\ -{\ - return rb_funcall(x, id_##n, 0);\ -} - -#define fun2(n) \ -inline static VALUE \ -f_##n(VALUE x, VALUE y)\ -{\ - return rb_funcall(x, id_##n, 1, y);\ -} - #define PRESERVE_SIGNEDZERO inline static VALUE @@ -275,8 +262,6 @@ f_to_f(VALUE x) return rb_funcall(x, id_to_f, 0); } -fun1(to_r) - inline static int f_eqeq_p(VALUE x, VALUE y) { @@ -287,8 +272,18 @@ f_eqeq_p(VALUE x, VALUE y) return (int)rb_equal(x, y); } -fun2(expt) -fun2(fdiv) +static VALUE +f_fdiv(VALUE x, VALUE y) +{ + if (RB_INTEGER_TYPE_P(x)) + return rb_int_fdiv(x, y); + if (RB_FLOAT_TYPE_P(x)) + return rb_float_div(x, y); + if (RB_TYPE_P(x, T_RATIONAL)) + return rb_rational_fdiv(x, y); + + return rb_funcallv(x, id_fdiv, 1, &y); +} static VALUE f_quo(VALUE x, VALUE y) @@ -317,24 +312,6 @@ f_negative_p(VALUE x) #define f_positive_p(x) (!f_negative_p(x)) -inline static bool -f_zero_p(VALUE x) -{ - if (RB_FLOAT_TYPE_P(x)) { - return FLOAT_ZERO_P(x); - } - else if (RB_INTEGER_TYPE_P(x)) { - return FIXNUM_ZERO_P(x); - } - else if (RB_TYPE_P(x, T_RATIONAL)) { - const VALUE num = RRATIONAL(x)->num; - return FIXNUM_ZERO_P(num); - } - return rb_equal(x, ZERO) != 0; -} - -#define f_nonzero_p(x) (!f_zero_p(x)) - static inline bool always_finite_type_p(VALUE x) { @@ -392,12 +369,11 @@ k_numeric_p(VALUE x) inline static VALUE nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag) { - NEWOBJ_OF(obj, struct RComplex, klass, - T_COMPLEX | (RGENGC_WB_PROTECTED_COMPLEX ? FL_WB_PROTECTED : 0), sizeof(struct RComplex), 0); + NEWOBJ_OF(obj, struct RComplex, klass, T_COMPLEX, sizeof(struct RComplex)); RCOMPLEX_SET_REAL(obj, real); RCOMPLEX_SET_IMAG(obj, imag); - OBJ_FREEZE_RAW((VALUE)obj); + OBJ_FREEZE((VALUE)obj); return (VALUE)obj; } @@ -411,15 +387,15 @@ nucomp_s_alloc(VALUE klass) inline static VALUE f_complex_new_bang1(VALUE klass, VALUE x) { - assert(!RB_TYPE_P(x, T_COMPLEX)); + RUBY_ASSERT(!RB_TYPE_P(x, T_COMPLEX)); return nucomp_s_new_internal(klass, x, ZERO); } inline static VALUE f_complex_new_bang2(VALUE klass, VALUE x, VALUE y) { - assert(!RB_TYPE_P(x, T_COMPLEX)); - assert(!RB_TYPE_P(y, T_COMPLEX)); + RUBY_ASSERT(!RB_TYPE_P(x, T_COMPLEX)); + RUBY_ASSERT(!RB_TYPE_P(y, T_COMPLEX)); return nucomp_s_new_internal(klass, x, y); } @@ -432,7 +408,7 @@ nucomp_real_check(VALUE num) !RB_TYPE_P(num, T_RATIONAL)) { if (RB_TYPE_P(num, T_COMPLEX) && nucomp_real_p(num)) { VALUE real = RCOMPLEX(num)->real; - assert(!RB_TYPE_P(real, T_COMPLEX)); + RUBY_ASSERT(!RB_TYPE_P(real, T_COMPLEX)); return real; } if (!k_numeric_p(num) || !f_real_p(num)) @@ -757,8 +733,8 @@ nucomp_s_polar(int argc, VALUE *argv, VALUE klass) * * Returns the real value for +self+: * - * Complex(7).real #=> 7 - * Complex(9, -4).real #=> 9 + * Complex.rect(7).real # => 7 + * Complex.rect(9, -4).real # => 9 * * If +self+ was created with * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value @@ -780,8 +756,8 @@ rb_complex_real(VALUE self) * * Returns the imaginary value for +self+: * - * Complex(7).imaginary #=> 0 - * Complex(9, -4).imaginary #=> -4 + * Complex.rect(7).imag # => 0 + * Complex.rect(9, -4).imag # => -4 * * If +self+ was created with * {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value @@ -799,12 +775,12 @@ rb_complex_imag(VALUE self) /* * call-seq: - * -complex -> new_complex + * -self -> complex * - * Returns the negation of +self+, which is the negation of each of its parts: + * Returns +self+, negated, which is the negation of each of its parts: * - * -Complex(1, 2) # => (-1-2i) - * -Complex(-1, -2) # => (1+2i) + * -Complex.rect(1, 2) # => (-1-2i) + * -Complex.rect(-1, -2) # => (1+2i) * */ VALUE @@ -816,17 +792,26 @@ rb_complex_uminus(VALUE self) } /* - * call-seq: - * complex + numeric -> new_complex + * call-seq: + * self + other -> numeric + * + * Returns the sum of +self+ and +other+: + * + * Complex(1, 2) + 0 # => (1+2i) + * Complex(1, 2) + 1 # => (2+2i) + * Complex(1, 2) + -1 # => (0+2i) * - * Returns the sum of +self+ and +numeric+: + * Complex(1, 2) + 1.0 # => (2.0+2i) * - * Complex(2, 3) + Complex(2, 3) # => (4+6i) - * Complex(900) + Complex(1) # => (901+0i) - * Complex(-2, 9) + Complex(-9, 2) # => (-11+11i) - * Complex(9, 8) + 4 # => (13+8i) - * Complex(20, 9) + 9.8 # => (29.8+9i) + * Complex(1, 2) + Complex(2, 1) # => (3+3i) + * Complex(1, 2) + Complex(2.0, 1.0) # => (3.0+3.0i) * + * Complex(1, 2) + Rational(1, 1) # => ((2/1)+2i) + * Complex(1, 2) + Rational(1, 2) # => ((3/2)+2i) + * + * For a computation involving Floats, the result may be inexact (see Float#+): + * + * Complex(1, 2) + 3.14 # => (4.140000000000001+2i) */ VALUE rb_complex_plus(VALUE self, VALUE other) @@ -852,15 +837,15 @@ rb_complex_plus(VALUE self, VALUE other) /* * call-seq: - * complex - numeric -> new_complex + * self - other -> complex * - * Returns the difference of +self+ and +numeric+: + * Returns the difference of +self+ and +other+: * - * Complex(2, 3) - Complex(2, 3) # => (0+0i) - * Complex(900) - Complex(1) # => (899+0i) - * Complex(-2, 9) - Complex(-9, 2) # => (7+7i) - * Complex(9, 8) - 4 # => (5+8i) - * Complex(20, 9) - 9.8 # => (10.2+9i) + * Complex.rect(2, 3) - Complex.rect(2, 3) # => (0+0i) + * Complex.rect(900) - Complex.rect(1) # => (899+0i) + * Complex.rect(-2, 9) - Complex.rect(-9, 2) # => (7+7i) + * Complex.rect(9, 8) - 4 # => (5+8i) + * Complex.rect(20, 9) - 9.8 # => (10.2+9i) * */ VALUE @@ -913,15 +898,16 @@ comp_mul(VALUE areal, VALUE aimag, VALUE breal, VALUE bimag, VALUE *real, VALUE /* * call-seq: - * complex * numeric -> new_complex + * self * other -> numeric * - * Returns the product of +self+ and +numeric+: + * Returns the numeric product of +self+ and +other+: * - * Complex(2, 3) * Complex(2, 3) # => (-5+12i) - * Complex(900) * Complex(1) # => (900+0i) - * Complex(-2, 9) * Complex(-9, 2) # => (0-85i) - * Complex(9, 8) * 4 # => (36+32i) - * Complex(20, 9) * 9.8 # => (196.0+88.2i) + * Complex.rect(9, 8) * 4 # => (36+32i) + * Complex.rect(20, 9) * 9.8 # => (196.0+88.2i) + * Complex.rect(2, 3) * Complex.rect(2, 3) # => (-5+12i) + * Complex.rect(900) * Complex.rect(1) # => (900+0i) + * Complex.rect(-2, 9) * Complex.rect(-9, 2) # => (0-85i) + * Complex.rect(9, 8) * Rational(2, 3) # => ((6/1)+(16/3)*i) * */ VALUE @@ -989,15 +975,15 @@ f_divide(VALUE self, VALUE other, /* * call-seq: - * complex / numeric -> new_complex + * self / other -> complex * - * Returns the quotient of +self+ and +numeric+: + * Returns the quotient of +self+ and +other+: * - * Complex(2, 3) / Complex(2, 3) # => ((1/1)+(0/1)*i) - * Complex(900) / Complex(1) # => ((900/1)+(0/1)*i) - * Complex(-2, 9) / Complex(-9, 2) # => ((36/85)-(77/85)*i) - * Complex(9, 8) / 4 # => ((9/4)+(2/1)*i) - * Complex(20, 9) / 9.8 # => (2.0408163265306123+0.9183673469387754i) + * Complex.rect(2, 3) / Complex.rect(2, 3) # => (1+0i) + * Complex.rect(900) / Complex.rect(1) # => (900+0i) + * Complex.rect(-2, 9) / Complex.rect(-9, 2) # => ((36/85)-(77/85)*i) + * Complex.rect(9, 8) / 4 # => ((9/4)+2i) + * Complex.rect(20, 9) / 9.8 # => (2.0408163265306123+0.9183673469387754i) * */ VALUE @@ -1012,9 +998,9 @@ rb_complex_div(VALUE self, VALUE other) * call-seq: * fdiv(numeric) -> new_complex * - * Returns <tt>Complex(self.real/numeric, self.imag/numeric)</tt>: + * Returns <tt>Complex.rect(self.real/numeric, self.imag/numeric)</tt>: * - * Complex(11, 22).fdiv(3) # => (3.6666666666666665+7.333333333333333i) + * Complex.rect(11, 22).fdiv(3) # => (3.6666666666666665+7.333333333333333i) * */ static VALUE @@ -1066,8 +1052,11 @@ complex_pow_for_special_angle(VALUE self, VALUE other) x = dat->imag; dir = 3; } + else { + dir = 0; + } - if (x == Qundef) return x; + if (UNDEF_P(x)) return x; if (f_negative_p(x)) { x = f_negate(x); @@ -1109,12 +1098,12 @@ complex_pow_for_special_angle(VALUE self, VALUE other) /* * call-seq: - * complex ** numeric -> new_complex + * self ** exponent -> complex * - * Returns +self+ raised to power +numeric+: + * Returns +self+ raised to the power +exponent+: * - * Complex('i') ** 2 # => (-1+0i) - * Complex(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i) + * Complex.rect(0, 1) ** 2 # => (-1+0i) + * Complex.rect(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i) * */ VALUE @@ -1139,7 +1128,7 @@ rb_complex_pow(VALUE self, VALUE other) } VALUE result = complex_pow_for_special_angle(self, other); - if (result != Qundef) return result; + if (!UNDEF_P(result)) return result; if (RB_TYPE_P(other, T_COMPLEX)) { VALUE r, theta, nr, ntheta; @@ -1202,23 +1191,22 @@ rb_complex_pow(VALUE self, VALUE other) if (RB_BIGNUM_TYPE_P(other)) rb_warn("in a**b, b may be too big"); - r = f_abs(self); - theta = f_arg(self); + r = rb_num_pow(f_abs(self), other); + theta = f_mul(f_arg(self), other); - return f_complex_polar(CLASS_OF(self), f_expt(r, other), - f_mul(theta, other)); + return f_complex_polar(CLASS_OF(self), r, theta); } return rb_num_coerce_bin(self, other, id_expt); } /* * call-seq: - * complex == object -> true or false + * self == other -> true or false * - * Returns +true+ if <tt>self.real == object.real</tt> - * and <tt>self.imag == object.imag</tt>: + * Returns whether both <tt>self.real == other.real</tt> + * and <tt>self.imag == other.imag</tt>: * - * Complex(2, 3) == Complex(2.0, 3.0) # => true + * Complex.rect(2, 3) == Complex.rect(2.0, 3.0) # => true * */ static VALUE @@ -1247,26 +1235,30 @@ nucomp_real_p(VALUE self) /* * call-seq: - * complex <=> object -> -1, 0, 1, or nil + * self <=> other -> -1, 0, 1, or nil + * + * Compares +self+ and +other+. * * Returns: * - * - <tt>self.real <=> object.real</tt> if both of the following are true: + * - <tt>self.real <=> other.real</tt> if both of the following are true: * * - <tt>self.imag == 0</tt>. - * - <tt>object.imag == 0</tt>. # Always true if object is numeric but not complex. + * - <tt>other.imag == 0</tt> (always true if +other+ is numeric but not complex). * * - +nil+ otherwise. * * Examples: * - * Complex(2) <=> 3 # => -1 - * Complex(2) <=> 2 # => 0 - * Complex(2) <=> 1 # => 1 - * Complex(2, 1) <=> 1 # => nil # self.imag not zero. - * Complex(1) <=> Complex(1, 1) # => nil # object.imag not zero. - * Complex(1) <=> 'Foo' # => nil # object.imag not defined. + * Complex.rect(2) <=> 3 # => -1 + * Complex.rect(2) <=> 2 # => 0 + * Complex.rect(2) <=> 1 # => 1 + * Complex.rect(2, 1) <=> 1 # => nil # self.imag not zero. + * Complex.rect(1) <=> Complex.rect(1, 1) # => nil # object.imag not zero. + * Complex.rect(1) <=> 'Foo' # => nil # object.imag not defined. * + * \Class \Complex includes module Comparable, + * each of whose methods uses Complex#<=> for comparison. */ static VALUE nucomp_cmp(VALUE self, VALUE other) @@ -1500,13 +1492,13 @@ nucomp_denominator(VALUE self) * {lowest common denominator}[https://en.wikipedia.org/wiki/Lowest_common_denominator] * of the two: * - * c = Complex(Rational(2, 3), Rational(3, 4)) # => ((2/3)+(3/4)*i) - * c.numerator # => (8+9i) + * c = Complex.rect(Rational(2, 3), Rational(3, 4)) # => ((2/3)+(3/4)*i) + * c.numerator # => (8+9i) * * In this example, the lowest common denominator of the two parts is 12; * the two converted parts may be thought of as \Rational(8, 12) and \Rational(9, 12), * whose numerators, respectively, are 8 and 9; - * so the returned value of <tt>c.numerator</tt> is <tt>Complex(8, 9)</tt>. + * so the returned value of <tt>c.numerator</tt> is <tt>Complex.rect(8, 9)</tt>. * * Related: Complex#denominator. */ @@ -1550,7 +1542,7 @@ rb_complex_hash(VALUE self) * Two \Complex objects created from the same values will have the same hash value * (and will compare using #eql?): * - * Complex(1, 2).hash == Complex(1, 2).hash # => true + * Complex.rect(1, 2).hash == Complex.rect(1, 2).hash # => true * */ static VALUE @@ -1591,16 +1583,15 @@ f_tpositive_p(VALUE x) } static VALUE -f_format(VALUE self, VALUE (*func)(VALUE)) +f_format(VALUE self, VALUE s, VALUE (*func)(VALUE)) { - VALUE s; int impos; get_dat1(self); impos = f_tpositive_p(dat->imag); - s = (*func)(dat->real); + rb_str_concat(s, (*func)(dat->real)); rb_str_cat2(s, !impos ? "-" : "+"); rb_str_concat(s, (*func)(f_abs(dat->imag))); @@ -1617,17 +1608,17 @@ f_format(VALUE self, VALUE (*func)(VALUE)) * * Returns a string representation of +self+: * - * Complex(2).to_s # => "2+0i" - * Complex('-8/6').to_s # => "-4/3+0i" - * Complex('1/2i').to_s # => "0+1/2i" - * Complex(0, Float::INFINITY).to_s # => "0+Infinity*i" - * Complex(Float::NAN, Float::NAN).to_s # => "NaN+NaN*i" + * Complex.rect(2).to_s # => "2+0i" + * Complex.rect(-8, 6).to_s # => "-8+6i" + * Complex.rect(0, Rational(1, 2)).to_s # => "0+1/2i" + * Complex.rect(0, Float::INFINITY).to_s # => "0+Infinity*i" + * Complex.rect(Float::NAN, Float::NAN).to_s # => "NaN+NaN*i" * */ static VALUE nucomp_to_s(VALUE self) { - return f_format(self, rb_String); + return f_format(self, rb_usascii_str_new2(""), rb_String); } /* @@ -1636,11 +1627,11 @@ nucomp_to_s(VALUE self) * * Returns a string representation of +self+: * - * Complex(2).inspect # => "(2+0i)" - * Complex('-8/6').inspect # => "((-4/3)+0i)" - * Complex('1/2i').inspect # => "(0+(1/2)*i)" - * Complex(0, Float::INFINITY).inspect # => "(0+Infinity*i)" - * Complex(Float::NAN, Float::NAN).inspect # => "(NaN+NaN*i)" + * Complex.rect(2).inspect # => "(2+0i)" + * Complex.rect(-8, 6).inspect # => "(-8+6i)" + * Complex.rect(0, Rational(1, 2)).inspect # => "(0+(1/2)*i)" + * Complex.rect(0, Float::INFINITY).inspect # => "(0+Infinity*i)" + * Complex.rect(Float::NAN, Float::NAN).inspect # => "(NaN+NaN*i)" * */ static VALUE @@ -1649,7 +1640,7 @@ nucomp_inspect(VALUE self) VALUE s; s = rb_usascii_str_new2("("); - rb_str_concat(s, f_format(self, rb_inspect)); + f_format(self, s, rb_inspect); rb_str_cat2(s, ")"); return s; @@ -1664,8 +1655,8 @@ nucomp_inspect(VALUE self) * Returns +true+ if both <tt>self.real.finite?</tt> and <tt>self.imag.finite?</tt> * are true, +false+ otherwise: * - * Complex(1, 1).finite? # => true - * Complex(Float::INFINITY, 0).finite? # => false + * Complex.rect(1, 1).finite? # => true + * Complex.rect(Float::INFINITY, 0).finite? # => false * * Related: Numeric#finite?, Float#finite?. */ @@ -1684,8 +1675,8 @@ rb_complex_finite_p(VALUE self) * Returns +1+ if either <tt>self.real.infinite?</tt> or <tt>self.imag.infinite?</tt> * is true, +nil+ otherwise: * - * Complex(Float::INFINITY, 0).infinite? # => 1 - * Complex(1, 1).infinite? # => nil + * Complex.rect(Float::INFINITY, 0).infinite? # => 1 + * Complex.rect(1, 1).infinite? # => nil * * Related: Numeric#infinite?, Float#infinite?. */ @@ -1715,7 +1706,7 @@ nucomp_loader(VALUE self, VALUE a) RCOMPLEX_SET_REAL(dat, rb_ivar_get(a, id_i_real)); RCOMPLEX_SET_IMAG(dat, rb_ivar_get(a, id_i_imag)); - OBJ_FREEZE_RAW(self); + OBJ_FREEZE(self); return self; } @@ -1763,12 +1754,6 @@ rb_complex_new_polar(VALUE x, VALUE y) } VALUE -rb_complex_polar(VALUE x, VALUE y) -{ - return rb_complex_new_polar(x, y); -} - -VALUE rb_Complex(VALUE x, VALUE y) { VALUE a[2]; @@ -1789,11 +1774,11 @@ rb_dbl_complex_new(double real, double imag) * * Returns the value of <tt>self.real</tt> as an Integer, if possible: * - * Complex(1, 0).to_i # => 1 - * Complex(1, Rational(0, 1)).to_i # => 1 + * Complex.rect(1, 0).to_i # => 1 + * Complex.rect(1, Rational(0, 1)).to_i # => 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>). */ static VALUE nucomp_to_i(VALUE self) @@ -1813,11 +1798,11 @@ nucomp_to_i(VALUE self) * * Returns the value of <tt>self.real</tt> as a Float, if possible: * - * Complex(1, 0).to_f # => 1.0 - * Complex(1, Rational(0, 1)).to_f # => 1.0 + * Complex.rect(1, 0).to_f # => 1.0 + * Complex.rect(1, Rational(0, 1)).to_f # => 1.0 * * 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>). */ static VALUE nucomp_to_f(VALUE self) @@ -1837,11 +1822,13 @@ nucomp_to_f(VALUE self) * * Returns the value of <tt>self.real</tt> as a Rational, if possible: * - * Complex(1, 0).to_r # => (1/1) - * Complex(1, Rational(0, 1)).to_r # => (1/1) + * 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. */ @@ -1850,11 +1837,17 @@ 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); + return rb_funcallv(dat->real, id_to_r, 0, 0); } /* @@ -1867,25 +1860,25 @@ nucomp_to_r(VALUE self) * With no argument +epsilon+ given, returns a \Rational object * whose value is exactly equal to that of <tt>self.real.rationalize</tt>: * - * Complex(1, 0).rationalize # => (1/1) - * Complex(1, Rational(0, 1)).rationalize # => (1/1) - * Complex(3.14159, 0).rationalize # => (314159/100000) + * Complex.rect(1, 0).rationalize # => (1/1) + * Complex.rect(1, Rational(0, 1)).rationalize # => (1/1) + * Complex.rect(3.14159, 0).rationalize # => (314159/100000) * * With argument +epsilon+ given, returns a \Rational object * whose value is exactly or approximately equal to that of <tt>self.real</tt> * to the given precision: * - * Complex(3.14159, 0).rationalize(0.1) # => (16/5) - * Complex(3.14159, 0).rationalize(0.01) # => (22/7) - * Complex(3.14159, 0).rationalize(0.001) # => (201/64) - * Complex(3.14159, 0).rationalize(0.0001) # => (333/106) - * Complex(3.14159, 0).rationalize(0.00001) # => (355/113) - * Complex(3.14159, 0).rationalize(0.000001) # => (7433/2366) - * Complex(3.14159, 0).rationalize(0.0000001) # => (9208/2931) - * Complex(3.14159, 0).rationalize(0.00000001) # => (47460/15107) - * Complex(3.14159, 0).rationalize(0.000000001) # => (76149/24239) - * Complex(3.14159, 0).rationalize(0.0000000001) # => (314159/100000) - * Complex(3.14159, 0).rationalize(0.0) # => (3537115888337719/1125899906842624) + * Complex.rect(3.14159, 0).rationalize(0.1) # => (16/5) + * Complex.rect(3.14159, 0).rationalize(0.01) # => (22/7) + * Complex.rect(3.14159, 0).rationalize(0.001) # => (201/64) + * Complex.rect(3.14159, 0).rationalize(0.0001) # => (333/106) + * Complex.rect(3.14159, 0).rationalize(0.00001) # => (355/113) + * Complex.rect(3.14159, 0).rationalize(0.000001) # => (7433/2366) + * Complex.rect(3.14159, 0).rationalize(0.0000001) # => (9208/2931) + * Complex.rect(3.14159, 0).rationalize(0.00000001) # => (47460/15107) + * Complex.rect(3.14159, 0).rationalize(0.000000001) # => (76149/24239) + * Complex.rect(3.14159, 0).rationalize(0.0000000001) # => (314159/100000) + * Complex.rect(3.14159, 0).rationalize(0.0) # => (3537115888337719/1125899906842624) * * Related: Complex#to_r. */ @@ -1917,21 +1910,6 @@ nucomp_to_c(VALUE self) /* * call-seq: - * to_c -> (0+0i) - * - * Returns zero as a Complex: - * - * nil.to_c # => (0+0i) - * - */ -static VALUE -nilclass_to_c(VALUE self) -{ - return rb_complex_new1(INT2FIX(0)); -} - -/* - * call-seq: * to_c -> complex * * Returns +self+ as a Complex object. @@ -2234,28 +2212,156 @@ string_to_c_strict(VALUE self, int raise) * call-seq: * to_c -> complex * - * Returns +self+ interpreted as a Complex object; - * leading whitespace and trailing garbage are ignored: - * - * '9'.to_c # => (9+0i) - * '2.5'.to_c # => (2.5+0i) - * '2.5/1'.to_c # => ((5/2)+0i) - * '-3/2'.to_c # => ((-3/2)+0i) - * '-i'.to_c # => (0-1i) - * '45i'.to_c # => (0+45i) - * '3-4i'.to_c # => (3-4i) - * '-4e2-4e-2i'.to_c # => (-400.0-0.04i) - * '-0.0-0.0i'.to_c # => (-0.0-0.0i) - * '1/2+3/4i'.to_c # => ((1/2)+(3/4)*i) - * '1.0@0'.to_c # => (1+0.0i) + * Returns a Complex object: + * parses the leading substring of +self+ + * to extract two numeric values that become the coordinates of the complex object. + * + * The substring is interpreted as containing + * either rectangular coordinates (real and imaginary parts) + * or polar coordinates (magnitude and angle parts), + * depending on an included or implied "separator" character: + * + * - <tt>'+'</tt>, <tt>'-'</tt>, or no separator: rectangular coordinates. + * - <tt>'@'</tt>: polar coordinates. + * + * <b>In Brief</b> + * + * In these examples, we use method Complex#rect to display rectangular coordinates, + * and method Complex#polar to display polar coordinates. + * + * # Rectangular coordinates. + * + * # Real-only: no separator; imaginary part is zero. + * '9'.to_c.rect # => [9, 0] # Integer. + * '-9'.to_c.rect # => [-9, 0] # Integer (negative). + * '2.5'.to_c.rect # => [2.5, 0] # Float. + * '1.23e-14'.to_c.rect # => [1.23e-14, 0] # Float with exponent. + * '2.5/1'.to_c.rect # => [(5/2), 0] # Rational. + * + * # Some things are ignored. + * 'foo1'.to_c.rect # => [0, 0] # Unparsed entire substring. + * '1foo'.to_c.rect # => [1, 0] # Unparsed trailing substring. + * ' 1 '.to_c.rect # => [1, 0] # Leading and trailing whitespace. + * * + * # Imaginary only: trailing 'i' required; real part is zero. + * '9i'.to_c.rect # => [0, 9] + * '-9i'.to_c.rect # => [0, -9] + * '2.5i'.to_c.rect # => [0, 2.5] + * '1.23e-14i'.to_c.rect # => [0, 1.23e-14] + * '2.5/1i'.to_c.rect # => [0, (5/2)] + * + * # Real and imaginary; '+' or '-' separator; trailing 'i' required. + * '2+3i'.to_c.rect # => [2, 3] + * '-2-3i'.to_c.rect # => [-2, -3] + * '2.5+3i'.to_c.rect # => [2.5, 3] + * '2.5+3/2i'.to_c.rect # => [2.5, (3/2)] + * + * # Polar coordinates; '@' separator; magnitude required. + * '1.0@0'.to_c.polar # => [1.0, 0.0] + * '1.0@'.to_c.polar # => [1.0, 0.0] + * "1.0@#{Math::PI}".to_c.polar # => [1.0, 3.141592653589793] + * "1.0@#{Math::PI/2}".to_c.polar # => [1.0, 1.5707963267948966] + * + * <b>Parsed Values</b> + * + * The parsing may be thought of as searching for numeric literals + * embedded in the substring. + * + * This section shows how the method parses numeric values from leading substrings. + * The examples show real-only or imaginary-only parsing; + * the parsing is the same for each part. + * + * '1foo'.to_c # => (1+0i) # Ignores trailing unparsed characters. + * ' 1 '.to_c # => (1+0i) # Ignores leading and trailing whitespace. + * 'x1'.to_c # => (0+0i) # Finds no leading numeric. + * + * # Integer literal embedded in the substring. + * '1'.to_c # => (1+0i) + * '-1'.to_c # => (-1+0i) + * '1i'.to_c # => (0+1i) + * + * # Integer literals that don't work. + * '0b100'.to_c # => (0+0i) # Not parsed as binary. + * '0o100'.to_c # => (0+0i) # Not parsed as octal. + * '0d100'.to_c # => (0+0i) # Not parsed as decimal. + * '0x100'.to_c # => (0+0i) # Not parsed as hexadecimal. + * '010'.to_c # => (10+0i) # Not parsed as octal. + * + * # Float literals: + * '3.14'.to_c # => (3.14+0i) + * '3.14i'.to_c # => (0+3.14i) + * '1.23e4'.to_c # => (12300.0+0i) + * '1.23e+4'.to_c # => (12300.0+0i) + * '1.23e-4'.to_c # => (0.000123+0i) + * + * # Rational literals: + * '1/2'.to_c # => ((1/2)+0i) + * '-1/2'.to_c # => ((-1/2)+0i) + * '1/2r'.to_c # => ((1/2)+0i) + * '-1/2r'.to_c # => ((-1/2)+0i) + * + * <b>Rectangular Coordinates</b> + * + * With separator <tt>'+'</tt> or <tt>'-'</tt>, + * or with no separator, + * interprets the values as rectangular coordinates: real and imaginary. + * + * With no separator, assigns a single value to either the real or the imaginary part: + * + * ''.to_c # => (0+0i) # Defaults to zero. + * '1'.to_c # => (1+0i) # Real (no trailing 'i'). + * '1i'.to_c # => (0+1i) # Imaginary (trailing 'i'). + * 'i'.to_c # => (0+1i) # Special case (imaginary 1). + * + * With separator <tt>'+'</tt>, both parts positive (or zero): + * + * # Without trailing 'i'. + * '+'.to_c # => (0+0i) # No values: defaults to zero. + * '+1'.to_c # => (1+0i) # Value after '+': real only. + * '1+'.to_c # => (1+0i) # Value before '+': real only. + * '2+1'.to_c # => (2+0i) # Values before and after '+': real and imaginary. + * # With trailing 'i'. + * '+1i'.to_c # => (0+1i) # Value after '+': imaginary only. + * '2+i'.to_c # => (2+1i) # Value before '+': real and imaginary 1. + * '2+1i'.to_c # => (2+1i) # Values before and after '+': real and imaginary. + * + * With separator <tt>'-'</tt>, negative imaginary part: + * + * # Without trailing 'i'. + * '-'.to_c # => (0+0i) # No values: defaults to zero. + * '-1'.to_c # => (-1+0i) # Value after '-': negative real, zero imaginary. + * '1-'.to_c # => (1+0i) # Value before '-': positive real, zero imaginary. + * '2-1'.to_c # => (2+0i) # Values before and after '-': positive real, zero imaginary. + * # With trailing 'i'. + * '-1i'.to_c # => (0-1i) # Value after '-': negative real, zero imaginary. + * '2-i'.to_c # => (2-1i) # Value before '-': positive real, negative imaginary. + * '2-1i'.to_c # => (2-1i) # Values before and after '-': positive real, negative imaginary. + * + * Note that the suffixed character <tt>'i'</tt> + * may instead be one of <tt>'I'</tt>, <tt>'j'</tt>, or <tt>'J'</tt>, + * with the same effect. + * + * <b>Polar Coordinates</b> + * + * With separator <tt>'@'</tt>) + * interprets the values as polar coordinates: magnitude and angle. + * + * '2@'.to_c.polar # => [2, 0.0] # Value before '@': magnitude only. + * # Values before and after '@': magnitude and angle. + * '2@1'.to_c.polar # => [2.0, 1.0] * "1.0@#{Math::PI/2}".to_c # => (0.0+1i) * "1.0@#{Math::PI}".to_c # => (-1+0.0i) + * # Magnitude not given: defaults to zero. + * '@'.to_c.polar # => [0, 0.0] + * '@1'.to_c.polar # => [0, 0.0] * - * Returns \Complex zero if the string cannot be converted: + * '1.0@0'.to_c # => (1+0.0i) * - * 'ruby'.to_c # => (0+0i) + * Note that in all cases, the suffixed character <tt>'i'</tt> + * may instead be one of <tt>'I'</tt>, <tt>'j'</tt>, <tt>'J'</tt>, + * with the same effect. * - * See Kernel#Complex. + * See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString]. */ static VALUE string_to_c(VALUE self) @@ -2280,7 +2386,7 @@ nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise) { if (NIL_P(a1) || NIL_P(a2)) { if (!raise) return Qnil; - rb_raise(rb_eTypeError, "can't convert nil into Complex"); + rb_cant_convert(Qnil, "Complex"); } if (RB_TYPE_P(a1, T_STRING)) { @@ -2460,14 +2566,14 @@ float_arg(VALUE self) * * The rectangular coordinates of a complex number * are called the _real_ and _imaginary_ parts; - * see {Complex number definition}[https://en.wikipedia.org/wiki/Complex_number#Definition]. + * see {Complex number definition}[https://en.wikipedia.org/wiki/Complex_number#Definition_and_basic_operations]. * * You can create a \Complex object from rectangular coordinates with: * - * - A {complex literal}[rdoc-ref:doc/syntax/literals.rdoc@Complex+Literals]. - * - \Method Complex.rect. - * - \Method Kernel#Complex, either with numeric arguments or with certain string arguments. - * - \Method String#to_c, for certain strings. + * - A {complex literal}[rdoc-ref:syntax/literals.rdoc@Complex+Literals]. + * - Method Complex.rect. + * - Method Kernel#Complex, either with numeric arguments or with certain string arguments. + * - Method String#to_c, for certain strings. * * Note that each of the stored parts may be a an instance one of the classes * Complex, Float, Integer, or Rational; @@ -2485,7 +2591,7 @@ float_arg(VALUE self) * * The polar coordinates of a complex number * are called the _absolute_ and _argument_ parts; - * see {Complex polar plane}[https://en.wikipedia.org/wiki/Complex_number#Polar_complex_plane]. + * see {Complex polar plane}[https://en.wikipedia.org/wiki/Complex_number#Polar_form]. * * In this class, the argument part * in expressed {radians}[https://en.wikipedia.org/wiki/Radian] @@ -2493,9 +2599,9 @@ float_arg(VALUE self) * * You can create a \Complex object from polar coordinates with: * - * - \Method Complex.polar. - * - \Method Kernel#Complex, with certain string arguments. - * - \Method String#to_c, for certain strings. + * - Method Complex.polar. + * - Method Kernel#Complex, with certain string arguments. + * - Method String#to_c, for certain strings. * * Note that each of the stored parts may be a an instance one of the classes * Complex, Float, Integer, or Rational; @@ -2509,6 +2615,80 @@ float_arg(VALUE self) * - Separately, with methods Complex#real and Complex#imag. * - Together, with method Complex#rect. * + * == What's Here + * + * First, what's elsewhere: + * + * - Class \Complex inherits (directly or indirectly) + * from classes {Numeric}[rdoc-ref:Numeric@Whats-Here] + * and {Object}[rdoc-ref:Object@Whats-Here]. + * - Includes (indirectly) module {Comparable}[rdoc-ref:Comparable@Whats-Here]. + * + * Here, class \Complex has methods for: + * + * === Creating \Complex Objects + * + * - ::polar: Returns a new \Complex object based on given polar coordinates. + * - ::rect (and its alias ::rectangular): + * Returns a new \Complex object based on given rectangular coordinates. + * + * === Querying + * + * - #abs (and its alias #magnitude): Returns the absolute value for +self+. + * - #arg (and its aliases #angle and #phase): + * Returns the argument (angle) for +self+ in radians. + * - #denominator: Returns the denominator of +self+. + * - #finite?: Returns whether both +self.real+ and +self.image+ are finite. + * - #hash: Returns the integer hash value for +self+. + * - #imag (and its alias #imaginary): Returns the imaginary value for +self+. + * - #infinite?: Returns whether +self.real+ or +self.image+ is infinite. + * - #numerator: Returns the numerator of +self+. + * - #polar: Returns the array <tt>[self.abs, self.arg]</tt>. + * - #inspect: Returns a string representation of +self+. + * - #real: Returns the real value for +self+. + * - #real?: Returns +false+; for compatibility with Numeric#real?. + * - #rect (and its alias #rectangular): + * Returns the array <tt>[self.real, self.imag]</tt>. + * + * === Comparing + * + * - #<=>: Returns whether +self+ is less than, equal to, or greater than the given argument. + * - #==: Returns whether +self+ is equal to the given argument. + * + * === Converting + * + * - #rationalize: Returns a Rational object whose value is exactly + * or approximately equivalent to that of <tt>self.real</tt>. + * - #to_c: Returns +self+. + * - #to_d: Returns the value as a BigDecimal object. + * - #to_f: Returns the value of <tt>self.real</tt> as a Float, if possible. + * - #to_i: Returns the value of <tt>self.real</tt> as an Integer, if possible. + * - #to_r: Returns the value of <tt>self.real</tt> as a Rational, if possible. + * - #to_s: Returns a string representation of +self+. + * + * === Performing Complex Arithmetic + * + * - #*: Returns the product of +self+ and the given numeric. + * - #**: Returns +self+ raised to power of the given numeric. + * - #+: Returns the sum of +self+ and the given numeric. + * - #-: Returns the difference of +self+ and the given numeric. + * - #-@: Returns the negation of +self+. + * - #/: Returns the quotient of +self+ and the given numeric. + * - #abs2: Returns square of the absolute value (magnitude) for +self+. + * - #conj (and its alias #conjugate): Returns the conjugate of +self+. + * - #fdiv: Returns <tt>Complex.rect(self.real/numeric, self.imag/numeric)</tt>. + * + * === Working with JSON + * + * - ::json_create: Returns a new \Complex object, + * deserialized from the given serialized hash. + * - #as_json: Returns a serialized hash constructed from +self+. + * - #to_json: Returns a JSON string representing +self+. + * + * These methods are provided by the {JSON gem}[https://github.com/ruby/json]. To make these methods available: + * + * require 'json/add/complex' + * */ void Init_Complex(void) @@ -2609,7 +2789,6 @@ Init_Complex(void) rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0); rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1); rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0); - rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0); rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0); rb_define_method(rb_cString, "to_c", string_to_c, 0); @@ -2630,7 +2809,7 @@ Init_Complex(void) /* * Equivalent - * to <tt>Complex(0, 1)</tt>: + * to <tt>Complex.rect(0, 1)</tt>: * * Complex::I # => (0+1i) * @@ -2639,7 +2818,7 @@ Init_Complex(void) f_complex_new_bang2(rb_cComplex, ZERO, ONE)); #if !USE_FLONUM - rb_gc_register_mark_object(RFLOAT_0 = DBL2NUM(0.0)); + rb_vm_register_global_object(RFLOAT_0 = DBL2NUM(0.0)); #endif rb_provide("complex.so"); /* for backward compatibility */ |
