ruby-changes:32261
From: naruse <ko1@a...>
Date: Sun, 22 Dec 2013 16:03:53 +0900 (JST)
Subject: [ruby-changes:32261] naruse:r44340: Release branch of Ruby 2.1
naruse 2013-12-22 16:00:55 +0900 (Sun, 22 Dec 2013) New Revision: 44340 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=44340 Log: Release branch of Ruby 2.1 Added directories: branches/ruby_2_1/ Index: ruby_2_1/complex.c =================================================================== --- ruby_2_1/complex.c (revision 0) +++ ruby_2_1/complex.c (revision 44340) @@ -0,0 +1,2256 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_1/complex.c#L1 +/* + complex.c: Coded by Tadayoshi Funaba 2008-2012 + + This implementation is based on Keiju Ishitsuka's Complex library + which is written in ruby. +*/ + +#include "ruby.h" +#include "internal.h" +#include <math.h> + +#define NDEBUG +#include <assert.h> + +#define ZERO INT2FIX(0) +#define ONE INT2FIX(1) +#define TWO INT2FIX(2) + +VALUE rb_cComplex; + +static ID id_abs, id_abs2, id_arg, id_cmp, id_conj, id_convert, + id_denominator, id_divmod, id_eqeq_p, id_expt, id_fdiv, id_floor, + id_idiv, id_imag, id_inspect, id_negate, id_numerator, id_quo, + id_real, id_real_p, id_to_f, id_to_i, id_to_r, id_to_s, + id_i_real, id_i_imag; + +#define f_boolcast(x) ((x) ? Qtrue : Qfalse) + +#define binop(n,op) \ +inline static VALUE \ +f_##n(VALUE x, VALUE y)\ +{\ + return rb_funcall(x, (op), 1, y);\ +} + +#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 math1(n) \ +inline static VALUE \ +m_##n(VALUE x)\ +{\ + return rb_funcall(rb_mMath, id_##n, 1, x);\ +} + +#define math2(n) \ +inline static VALUE \ +m_##n(VALUE x, VALUE y)\ +{\ + return rb_funcall(rb_mMath, id_##n, 2, x, y);\ +} + +#define PRESERVE_SIGNEDZERO + +inline static VALUE +f_add(VALUE x, VALUE y) +{ +#ifndef PRESERVE_SIGNEDZERO + if (FIXNUM_P(y) && FIX2LONG(y) == 0) + return x; + else if (FIXNUM_P(x) && FIX2LONG(x) == 0) + return y; +#endif + return rb_funcall(x, '+', 1, y); +} + +inline static VALUE +f_cmp(VALUE x, VALUE y) +{ + if (FIXNUM_P(x) && FIXNUM_P(y)) { + long c = FIX2LONG(x) - FIX2LONG(y); + if (c > 0) + c = 1; + else if (c < 0) + c = -1; + return INT2FIX(c); + } + return rb_funcall(x, id_cmp, 1, y); +} + +inline static VALUE +f_div(VALUE x, VALUE y) +{ + if (FIXNUM_P(y) && FIX2LONG(y) == 1) + return x; + return rb_funcall(x, '/', 1, y); +} + +inline static VALUE +f_gt_p(VALUE x, VALUE y) +{ + if (FIXNUM_P(x) && FIXNUM_P(y)) + return f_boolcast(FIX2LONG(x) > FIX2LONG(y)); + return rb_funcall(x, '>', 1, y); +} + +inline static VALUE +f_lt_p(VALUE x, VALUE y) +{ + if (FIXNUM_P(x) && FIXNUM_P(y)) + return f_boolcast(FIX2LONG(x) < FIX2LONG(y)); + return rb_funcall(x, '<', 1, y); +} + +binop(mod, '%') + +inline static VALUE +f_mul(VALUE x, VALUE y) +{ +#ifndef PRESERVE_SIGNEDZERO + if (FIXNUM_P(y)) { + long iy = FIX2LONG(y); + if (iy == 0) { + if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM)) + return ZERO; + } + else if (iy == 1) + return x; + } + else if (FIXNUM_P(x)) { + long ix = FIX2LONG(x); + if (ix == 0) { + if (FIXNUM_P(y) || RB_TYPE_P(y, T_BIGNUM)) + return ZERO; + } + else if (ix == 1) + return y; + } +#endif + return rb_funcall(x, '*', 1, y); +} + +inline static VALUE +f_sub(VALUE x, VALUE y) +{ +#ifndef PRESERVE_SIGNEDZERO + if (FIXNUM_P(y) && FIX2LONG(y) == 0) + return x; +#endif + return rb_funcall(x, '-', 1, y); +} + +fun1(abs) +fun1(abs2) +fun1(arg) +fun1(conj) +fun1(denominator) +fun1(floor) +fun1(imag) +fun1(inspect) +fun1(negate) +fun1(numerator) +fun1(real) +fun1(real_p) + +inline static VALUE +f_to_i(VALUE x) +{ + if (RB_TYPE_P(x, T_STRING)) + return rb_str_to_inum(x, 10, 0); + return rb_funcall(x, id_to_i, 0); +} +inline static VALUE +f_to_f(VALUE x) +{ + if (RB_TYPE_P(x, T_STRING)) + return DBL2NUM(rb_str_to_dbl(x, 0)); + return rb_funcall(x, id_to_f, 0); +} + +fun1(to_r) +fun1(to_s) + +fun2(divmod) + +inline static VALUE +f_eqeq_p(VALUE x, VALUE y) +{ + if (FIXNUM_P(x) && FIXNUM_P(y)) + return f_boolcast(FIX2LONG(x) == FIX2LONG(y)); + return rb_funcall(x, id_eqeq_p, 1, y); +} + +fun2(expt) +fun2(fdiv) +fun2(idiv) +fun2(quo) + +inline static VALUE +f_negative_p(VALUE x) +{ + if (FIXNUM_P(x)) + return f_boolcast(FIX2LONG(x) < 0); + return rb_funcall(x, '<', 1, ZERO); +} + +#define f_positive_p(x) (!f_negative_p(x)) + +inline static VALUE +f_zero_p(VALUE x) +{ + if (RB_TYPE_P(x, T_FIXNUM)) { + return f_boolcast(FIX2LONG(x) == 0); + } + else if (RB_TYPE_P(x, T_BIGNUM)) { + return Qfalse; + } + else if (RB_TYPE_P(x, T_RATIONAL)) { + VALUE num = RRATIONAL(x)->num; + + return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0); + } + return rb_funcall(x, id_eqeq_p, 1, ZERO); +} + +#define f_nonzero_p(x) (!f_zero_p(x)) + +inline static VALUE +f_one_p(VALUE x) +{ + if (RB_TYPE_P(x, T_FIXNUM)) { + return f_boolcast(FIX2LONG(x) == 1); + } + else if (RB_TYPE_P(x, T_BIGNUM)) { + return Qfalse; + } + else if (RB_TYPE_P(x, T_RATIONAL)) { + VALUE num = RRATIONAL(x)->num; + VALUE den = RRATIONAL(x)->den; + + return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 1 && + FIXNUM_P(den) && FIX2LONG(den) == 1); + } + return rb_funcall(x, id_eqeq_p, 1, ONE); +} + +inline static VALUE +f_kind_of_p(VALUE x, VALUE c) +{ + return rb_obj_is_kind_of(x, c); +} + +inline static VALUE +k_numeric_p(VALUE x) +{ + return f_kind_of_p(x, rb_cNumeric); +} + +inline static VALUE +k_integer_p(VALUE x) +{ + return f_kind_of_p(x, rb_cInteger); +} + +inline static VALUE +k_fixnum_p(VALUE x) +{ + return f_kind_of_p(x, rb_cFixnum); +} + +inline static VALUE +k_bignum_p(VALUE x) +{ + return f_kind_of_p(x, rb_cBignum); +} + +inline static VALUE +k_float_p(VALUE x) +{ + return f_kind_of_p(x, rb_cFloat); +} + +inline static VALUE +k_rational_p(VALUE x) +{ + return f_kind_of_p(x, rb_cRational); +} + +inline static VALUE +k_complex_p(VALUE x) +{ + return f_kind_of_p(x, rb_cComplex); +} + +#define k_exact_p(x) (!k_float_p(x)) +#define k_inexact_p(x) k_float_p(x) + +#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x)) +#define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x)) + +#define get_dat1(x) \ + struct RComplex *dat;\ + dat = ((struct RComplex *)(x)) + +#define get_dat2(x,y) \ + struct RComplex *adat, *bdat;\ + adat = ((struct RComplex *)(x));\ + bdat = ((struct RComplex *)(y)) + +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)); + + RCOMPLEX_SET_REAL(obj, real); + RCOMPLEX_SET_IMAG(obj, imag); + + return (VALUE)obj; +} + +static VALUE +nucomp_s_alloc(VALUE klass) +{ + return nucomp_s_new_internal(klass, ZERO, ZERO); +} + +#if 0 +static VALUE +nucomp_s_new_bang(int argc, VALUE *argv, VALUE klass) +{ + VALUE real, imag; + + switch (rb_scan_args(argc, argv, "11", &real, &imag)) { + case 1: + if (!k_numeric_p(real)) + real = f_to_i(real); + imag = ZERO; + break; + default: + if (!k_numeric_p(real)) + real = f_to_i(real); + if (!k_numeric_p(imag)) + imag = f_to_i(imag); + break; + } + + return nucomp_s_new_internal(klass, real, imag); +} +#endif + +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); +} + +#ifdef CANONICALIZATION_FOR_MATHN +#define CANON +#endif + +#ifdef CANON +static int canonicalization = 0; + +RUBY_FUNC_EXPORTED void +nucomp_canonicalization(int f) +{ + canonicalization = f; +} +#endif + +inline static void +nucomp_real_check(VALUE num) +{ + if (!RB_TYPE_P(num, T_FIXNUM) && + !RB_TYPE_P(num, T_BIGNUM) && + !RB_TYPE_P(num, T_FLOAT) && + !RB_TYPE_P(num, T_RATIONAL)) { + if (!k_numeric_p(num) || !f_real_p(num)) + rb_raise(rb_eTypeError, "not a real"); + } +} + +inline static VALUE +nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag) +{ +#ifdef CANON +#define CL_CANON +#ifdef CL_CANON + if (k_exact_zero_p(imag) && canonicalization) + return real; +#else + if (f_zero_p(imag) && canonicalization) + return real; +#endif +#endif + if (f_real_p(real) && f_real_p(imag)) + return nucomp_s_new_internal(klass, real, imag); + else if (f_real_p(real)) { + get_dat1(imag); + + return nucomp_s_new_internal(klass, + f_sub(real, dat->imag), + f_add(ZERO, dat->real)); + } + else if (f_real_p(imag)) { + get_dat1(real); + + return nucomp_s_new_internal(klass, + dat->real, + f_add(dat->imag, imag)); + } + else { + get_dat2(real, imag); + + return nucomp_s_new_internal(klass, + f_sub(adat->real, bdat->imag), + f_add(adat->imag, bdat->real)); + } +} + +/* + * call-seq: + * Complex.rect(real[, imag]) -> complex + * Complex.rectangular(real[, imag]) -> complex + * + * Returns a complex object which denotes the given rectangular form. + * + * Complex.rectangular(1, 2) #=> (1+2i) + */ +static VALUE +nucomp_s_new(int argc, VALUE *argv, VALUE klass) +{ + VALUE real, imag; + + switch (rb_scan_args(argc, argv, "11", &real, &imag)) { + case 1: + nucomp_real_check(real); + imag = ZERO; + break; + default: + nucomp_real_check(real); + nucomp_real_check(imag); + break; + } + + return nucomp_s_canonicalize_internal(klass, real, imag); +} + +inline static VALUE +f_complex_new1(VALUE klass, VALUE x) +{ + assert(!k_complex_p(x)); + return nucomp_s_canonicalize_internal(klass, x, ZERO); +} + +inline static VALUE +f_complex_new2(VALUE klass, VALUE x, VALUE y) +{ + assert(!k_complex_p(x)); + return nucomp_s_canonicalize_internal(klass, x, y); +} + +/* + * call-seq: + * Complex(x[, y]) -> numeric + * + * Returns x+i*y; + * + * Complex(1, 2) #=> (1+2i) + * Complex('1+2i') #=> (1+2i) + * + * Syntax of string form: + * + * string form = extra spaces , complex , extra spaces ; + * complex = real part | [ sign ] , imaginary part + * | real part , sign , imaginary part + * | rational , "@" , rational ; + * real part = rational ; + * imaginary part = imaginary unit | unsigned rational , imaginary unit ; + * rational = [ sign ] , unsigned rational ; + * unsigned rational = numerator | numerator , "/" , denominator ; + * numerator = integer part | fractional part | integer part , fractional part ; + * denominator = digits ; + * integer part = digits ; + * fractional part = "." , digits , [ ( "e" | "E" ) , [ sign ] , digits ] ; + * imaginary unit = "i" | "I" | "j" | "J" ; + * sign = "-" | "+" ; + * digits = digit , { digit | "_" , digit }; + * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; + * extra spaces = ? \s* ? ; + * + * See String#to_c. + */ +static VALUE +nucomp_f_complex(int argc, VALUE *argv, VALUE klass) +{ + return rb_funcall2(rb_cComplex, id_convert, argc, argv); +} + +#define imp1(n) \ +inline static VALUE \ +m_##n##_bang(VALUE x)\ +{\ + return rb_math_##n(x);\ +} + +#define imp2(n) \ +inline static VALUE \ +m_##n##_bang(VALUE x, VALUE y)\ +{\ + return rb_math_##n(x, y);\ +} + +imp2(atan2) +imp1(cos) +imp1(cosh) +imp1(exp) +imp2(hypot) + +#define m_hypot(x,y) m_hypot_bang((x),(y)) + +static VALUE +m_log_bang(VALUE x) +{ + return rb_math_log(1, &x); +} + +imp1(sin) +imp1(sinh) +imp1(sqrt) + +static VALUE +m_cos(VALUE x) +{ + if (f_real_p(x)) + return m_cos_bang(x); + { + get_dat1(x); + return f_complex_new2(rb_cComplex, + f_mul(m_cos_bang(dat->real), + m_cosh_bang(dat->imag)), + f_mul(f_negate(m_sin_bang(dat->real)), + m_sinh_bang(dat->imag))); + } +} + +static VALUE +m_sin(VALUE x) +{ + if (f_real_p(x)) + return m_sin_bang(x); + { + get_dat1(x); + return f_complex_new2(rb_cComplex, + f_mul(m_sin_bang(dat->real), + m_cosh_bang(dat->imag)), + f_mul(m_cos_bang(dat->real), + m_sinh_bang(dat->imag))); + } +} + +#if 0 +static VALUE +m_sqrt(VALUE x) +{ + if (f_real_p(x)) { + if (f_positive_p(x)) + return m_sqrt_bang(x); + return f_complex_new2(rb_cComplex, ZERO, m_sqrt_bang(f_negate(x))); + } + else { + get_dat1(x); + + if (f_negative_p(dat->imag)) + return f_conj(m_sqrt(f_conj(x))); + else { + VALUE a = f_abs(x); + return f_complex_new2(rb_cComplex, + m_sqrt_bang(f_div(f_add(a, dat->real), TWO)), + m_sqrt_bang(f_div(f_sub(a, dat->real), TWO))); + } + } +} +#endif + +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))); +} + +/* + * call-seq: + * Complex.polar(abs[, arg]) -> complex + * + * Returns a complex object which denotes the given polar form. + * + * Complex.polar(3, 0) #=> (3.0+0.0i) + * Complex.polar(3, Math::PI/2) #=> (1.836909530733566e-16+3.0i) + * Complex.polar(3, Math::PI) #=> (-3.0+3.673819061467132e-16i) + * Complex.polar(3, -Math::PI/2) #=> (1.836909530733566e-16-3.0i) + */ +static VALUE +nucomp_s_polar(int argc, VALUE *argv, VALUE klass) +{ + VALUE abs, arg; + + switch (rb_scan_args(argc, argv, "11", &abs, &arg)) { + case 1: + nucomp_real_check(abs); + arg = ZERO; + break; + default: + nucomp_real_check(abs); + nucomp_real_check(arg); + break; + } + return f_complex_polar(klass, abs, arg); +} + +/* + * call-seq: + * cmp.real -> real + * + * Returns the real part. + * + * Complex(7).real #=> 7 + * Complex(9, -4).real #=> 9 + */ +static VALUE +nucomp_real(VALUE self) +{ + get_dat1(self); + return dat->real; +} + +/* + * call-seq: + * cmp.imag -> real + * cmp.imaginary -> real + * + * Returns the imaginary part. + * + * Complex(7).imaginary #=> 0 + * Complex(9, -4).imaginary #=> -4 + */ +static VALUE +nucomp_imag(VALUE self) +{ + get_dat1(self); + return dat->imag; +} + +/* + * call-seq: + * -cmp -> complex + * + * Returns negation of the value. + * + * -Complex(1, 2) #=> (-1-2i) + */ +static VALUE +nucomp_negate(VALUE self) +{ + get_dat1(self); + return f_complex_new2(CLASS_OF(self), + f_negate(dat->real), f_negate(dat->imag)); +} + +inline static VALUE +f_addsub(VALUE self, VALUE other, + VALUE (*func)(VALUE, VALUE), ID id) +{ + if (k_complex_p(other)) { + VALUE real, imag; + + get_dat2(self, other); + + real = (*func)(adat->real, bdat->real); + imag = (*func)(adat->imag, bdat->imag); + + return f_complex_new2(CLASS_OF(self), real, imag); + } + if (k_numeric_p(other) && f_real_p(other)) { + get_dat1(self); + + return f_complex_new2(CLASS_OF(self), + (*func)(dat->real, other), dat->imag); + } + return rb_num_coerce_bin(self, other, id); +} + +/* + * call-seq: + * cmp + numeric -> complex + * + * Performs addition. + * + * 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) + */ +static VALUE +nucomp_add(VALUE self, VALUE other) +{ + return f_addsub(self, other, f_add, '+'); +} + +/* + * call-seq: + * cmp - numeric -> complex + * + * Performs subtraction. + * + * 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) + */ +static VALUE +nucomp_sub(VALUE self, VALUE other) +{ + return f_addsub(self, other, f_sub, '-'); +} + +/* + * call-seq: + * cmp * numeric -> complex + * + * Performs multiplication. + * + * 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) + */ +static VALUE +nucomp_mul(VALUE self, VALUE other) +{ + if (k_complex_p(other)) { + VALUE real, imag; + + get_dat2(self, other); + + real = f_sub(f_mul(adat->real, bdat->real), + f_mul(adat->imag, bdat->imag)); + imag = f_add(f_mul(adat->real, bdat->imag), + f_mul(adat->imag, bdat->real)); + + return f_complex_new2(CLASS_OF(self), real, imag); + } + if (k_numeric_p(other) && f_real_p(other)) { + get_dat1(self); + + return f_complex_new2(CLASS_OF(self), + f_mul(dat->real, other), + f_mul(dat->imag, other)); + } + return rb_num_coerce_bin(self, other, '*'); +} + +inline static VALUE +f_divide(VALUE self, VALUE other, + VALUE (*func)(VALUE, VALUE), ID id) +{ + if (k_complex_p(other)) { + int flo; + get_dat2(self, other); + + flo = (k_float_p(adat->real) || k_float_p(adat->imag) || + k_float_p(bdat->real) || k_float_p(bdat->imag)); + + if (f_gt_p(f_abs(bdat->real), f_abs(bdat->imag))) { + VALUE r, n; + + r = (*func)(bdat->imag, bdat->real); + n = f_mul(bdat->real, f_add(ONE, f_mul(r, r))); + if (flo) + return f_complex_new2(CLASS_OF(self), + (*func)(self, n), + (*func)(f_negate(f_mul(self, r)), n)); + return f_complex_new2(CLASS_OF(self), + (*func)(f_add(adat->real, + f_mul(adat->imag, r)), n), + (*func)(f_sub(adat->imag, + f_mul(adat->real, r)), n)); + } + else { + VALUE r, n; + + r = (*func)(bdat->real, bdat->imag); + n = f_mul(bdat->imag, f_add(ONE, f_mul(r, r))); + if (flo) + return f_complex_new2(CLASS_OF(self), + (*func)(f_mul(self, r), n), + (*func)(f_negate(self), n)); + return f_complex_new2(CLASS_OF(self), + (*func)(f_add(f_mul(adat->real, r), + adat->imag), n), + (*func)(f_sub(f_mul(adat->imag, r), + adat->real), n)); + } + } + if (k_numeric_p(other) && f_real_p(other)) { + get_dat1(self); + + return f_complex_new2(CLASS_OF(self), + (*func)(dat->real, other), + (*func)(dat->imag, other)); + } + return rb_num_coerce_bin(self, other, id); +} + +#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0") + +/* + * call-seq: + * cmp / numeric -> complex + * cmp.quo(numeric) -> complex + * + * Performs division. + * + * 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) + */ +static VALUE +nucomp_div(VALUE self, VALUE other) +{ + return f_divide(self, other, f_quo, id_quo); +} + +#define nucomp_quo nucomp_div + +/* + * call-seq: + * cmp.fdiv(numeric) -> complex + * + * Performs division as each part is a float, never returns a float. + * + * Complex(11, 22).fdiv(3) #=> (3.6666666666666665+7.333333333333333i) + */ +static VALUE +nucomp_fdiv(VALUE self, VALUE other) +{ + return f_divide(self, other, f_fdiv, id_fdiv); +} + +inline static VALUE +f_reciprocal(VALUE x) +{ + return f_quo(ONE, x); +} + +/* + * call-seq: + * cmp ** numeric -> complex + * + * Performs exponentiation. + * + * Complex('i') ** 2 #=> (-1+0i) + * Complex(-8) ** Rational(1, 3) #=> (1.0000000000000002+1.7320508075688772i) + */ +static VALUE +nucomp_expt(VALUE self, VALUE other) +{ + if (k_numeric_p(other) && k_exact_zero_p(other)) + return f_complex_new_bang1(CLASS_OF(self), ONE); + + if (k_rational_p(other) && f_one_p(f_denominator(other))) + other = f_numerator(other); /* c14n */ + + if (k_complex_p(other)) { + get_dat1(other); + + if (k_exact_zero_p(dat->imag)) + other = dat->real; /* c14n */ + } + + i (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/