diff options
Diffstat (limited to 'complex.c')
| -rw-r--r-- | complex.c | 328 |
1 files changed, 212 insertions, 116 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,8 +369,7 @@ 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); @@ -799,9 +775,9 @@ 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.rect(1, 2) # => (-1-2i) * -Complex.rect(-1, -2) # => (1+2i) @@ -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+: * - * Returns the sum of +self+ and +numeric+: + * Complex(1, 2) + 0 # => (1+2i) + * Complex(1, 2) + 1 # => (2+2i) + * Complex(1, 2) + -1 # => (0+2i) * - * Complex.rect(2, 3) + Complex.rect(2, 3) # => (4+6i) - * Complex.rect(900) + Complex.rect(1) # => (901+0i) - * Complex.rect(-2, 9) + Complex.rect(-9, 2) # => (-11+11i) - * Complex.rect(9, 8) + 4 # => (13+8i) - * Complex.rect(20, 9) + 9.8 # => (29.8+9i) + * Complex(1, 2) + 1.0 # => (2.0+2i) * + * 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,9 +837,9 @@ 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.rect(2, 3) - Complex.rect(2, 3) # => (0+0i) * Complex.rect(900) - Complex.rect(1) # => (899+0i) @@ -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.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) * 4 # => (36+32i) - * Complex.rect(20, 9) * 9.8 # => (196.0+88.2i) + * Complex.rect(9, 8) * Rational(2, 3) # => ((6/1)+(16/3)*i) * */ VALUE @@ -989,9 +975,9 @@ 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.rect(2, 3) / Complex.rect(2, 3) # => (1+0i) * Complex.rect(900) / Complex.rect(1) # => (900+0i) @@ -1065,7 +1051,8 @@ complex_pow_for_special_angle(VALUE self, VALUE other) else if (f_eqeq_p(dat->real, f_negate(dat->imag))) { x = dat->imag; dir = 3; - } else { + } + else { dir = 0; } @@ -1111,9 +1098,9 @@ 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.rect(0, 1) ** 2 # => (-1+0i) * Complex.rect(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i) @@ -1204,21 +1191,20 @@ 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.rect(2, 3) == Complex.rect(2.0, 3.0) # => true * @@ -1249,14 +1235,16 @@ 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. * @@ -1269,6 +1257,8 @@ nucomp_real_p(VALUE self) * 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) @@ -1764,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]; @@ -1794,7 +1778,7 @@ rb_dbl_complex_new(double real, double imag) * 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) @@ -1818,7 +1802,7 @@ nucomp_to_i(VALUE self) * 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) @@ -1843,7 +1827,7 @@ nucomp_to_f(VALUE self) * 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. @@ -1863,7 +1847,7 @@ nucomp_to_r(VALUE self) self); } } - return f_to_r(dat->real); + return rb_funcallv(dat->real, id_to_r, 0, 0); } /* @@ -1926,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. @@ -2243,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) @@ -2289,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)) { @@ -2523,9 +2620,9 @@ float_arg(VALUE self) * First, what's elsewhere: * * - Class \Complex inherits (directly or indirectly) - * from classes {Numeric}[rdoc-ref:Numeric@What-27s+Here] - * and {Object}[rdoc-ref:Object@What-27s+Here]. - * - Includes (indirectly) module {Comparable}[rdoc-ref:Comparable@What-27s+Here]. + * 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: * @@ -2692,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); |
