/* * call-seq: * cmp.abs2 -> real * * Returns square of the absolute value. * * Complex(-1).abs2 #=> 1 * Complex(3.0, -4.0).abs2 #=> 25.0 */ static VALUE nucomp_abs2(VALUE self) { get_dat1(self); return f_add(f_mul(dat->real, dat->real), f_mul(dat->imag, dat->imag)); }
static VALUE nucomp_div(VALUE self, VALUE other) { if (k_complex_p(other)) { get_dat2(self, other); if (TYPE(adat->real) == T_FLOAT || TYPE(adat->imag) == T_FLOAT || TYPE(bdat->real) == T_FLOAT || TYPE(bdat->imag) == T_FLOAT) { VALUE magn = m_hypot(bdat->real, bdat->imag); VALUE tmp = f_complex_new_bang2(CLASS_OF(self), f_div(bdat->real, magn), f_div(bdat->imag, magn)); return f_div(f_mul(self, f_conj(tmp)), magn); } return f_div(f_mul(self, f_conj(other)), f_abs2(other)); } if (k_numeric_p(other) && f_real_p(other)) { get_dat1(self); return f_complex_new2(CLASS_OF(self), f_div(dat->real, other), f_div(dat->imag, other)); } return rb_num_coerce_bin(self, other, '/'); }
/* * 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) */ VALUE rb_nucomp_mul(VALUE self, VALUE other) { if (k_complex_p(other)) { VALUE real, imag; VALUE areal, aimag, breal, bimag; int arzero, aizero, brzero, bizero; get_dat2(self, other); arzero = !!f_zero_p(areal = adat->real); aizero = !!f_zero_p(aimag = adat->imag); brzero = !!f_zero_p(breal = bdat->real); bizero = !!f_zero_p(bimag = bdat->imag); real = f_sub(safe_mul(areal, breal, arzero, brzero), safe_mul(aimag, bimag, aizero, bizero)); imag = f_add(safe_mul(areal, bimag, arzero, bizero), safe_mul(aimag, breal, aizero, brzero)); 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_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))); }
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); }
/* * call-seq: * cmp.numerator -> numeric * * Returns the numerator. * * 1 2 3+4i <- numerator * - + -i -> ---- * 2 3 6 <- denominator * * c = Complex('1/2+2/3i') #=> ((1/2)+(2/3)*i) * n = c.numerator #=> (3+4i) * d = c.denominator #=> 6 * n / d #=> ((1/2)+(2/3)*i) * Complex(Rational(n.real, d), Rational(n.imag, d)) * #=> ((1/2)+(2/3)*i) * See denominator. */ static VALUE nucomp_numerator(VALUE self) { VALUE cd; get_dat1(self); cd = f_denominator(self); return f_complex_new2(CLASS_OF(self), f_mul(f_numerator(dat->real), f_div(cd, f_denominator(dat->real))), f_mul(f_numerator(dat->imag), f_div(cd, f_denominator(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))); } }
inline static VALUE f_addsub(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) { VALUE num, den; if (FIXNUM_P(anum) && FIXNUM_P(aden) && FIXNUM_P(bnum) && FIXNUM_P(bden)) { long an = FIX2LONG(anum); long ad = FIX2LONG(aden); long bn = FIX2LONG(bnum); long bd = FIX2LONG(bden); long ig = i_gcd(ad, bd); VALUE g = LONG2NUM(ig); VALUE a = f_imul(an, bd / ig); VALUE b = f_imul(bn, ad / ig); VALUE c; if (k == '+') c = f_add(a, b); else c = f_sub(a, b); b = f_idiv(aden, g); g = f_gcd(c, g); num = f_idiv(c, g); a = f_idiv(bden, g); den = f_mul(a, b); } else { VALUE g = f_gcd(aden, bden); VALUE a = f_mul(anum, f_idiv(bden, g)); VALUE b = f_mul(bnum, f_idiv(aden, g)); VALUE c; if (k == '+') c = f_add(a, b); else c = f_sub(a, b); b = f_idiv(aden, g); g = f_gcd(c, g); num = f_idiv(c, g); a = f_idiv(bden, g); den = f_mul(a, b); } return f_rational_new_no_reduce2(CLASS_OF(self), num, den); }
inline static VALUE f_lcm(VALUE x, VALUE y) { if (f_zero_p(x) || f_zero_p(y)) return ZERO; return f_abs(f_mul(f_div(x, f_gcd(x, y)), y)); }
static VALUE float_to_r(VALUE self) { VALUE a = float_decode(self); return f_mul(RARRAY_AT(a, 0), f_expt(INT2FIX(FLT_RADIX), RARRAY_AT(a, 1))); }
static VALUE f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE, SEL)) { VALUE n, b, s; if (argc == 0) return (*func)(self, NULL); rb_scan_args(argc, argv, "01", &n); if (!k_integer_p(n)) rb_raise(rb_eTypeError, "not an integer"); b = f_expt(INT2FIX(10), n); s = f_mul(self, b); s = (*func)(s, NULL); s = f_div(f_rational_new_bang1(CLASS_OF(self), s), b); if (f_lt_p(n, ONE)) s = f_to_i(s); return s; }
/* * call-seq: * rat * numeric -> numeric_result * * Performs multiplication. * * For example: * * Rational(2, 3) * Rational(2, 3) #=> (4/9) * Rational(900) * Rational(1) #=> (900/1) * Rational(-2, 9) * Rational(-9, 2) #=> (1/1) * Rational(9, 8) * 4 #=> (9/2) * Rational(20, 9) * 9.8 #=> 21.77777777777778 */ static VALUE nurat_mul(VALUE self, SEL sel, VALUE other) { switch (TYPE(other)) { case T_FIXNUM: case T_BIGNUM: { get_dat1(self); return f_muldiv(self, dat->num, dat->den, other, ONE, '*'); } case T_FLOAT: return f_mul(f_to_f(self), other); case T_RATIONAL: { get_dat2(self, other); return f_muldiv(self, adat->num, adat->den, bdat->num, bdat->den, '*'); } default: return rb_num_coerce_bin(self, other, '*'); } }
inline static VALUE f_imul(long x, long y) { VALUE r = f_imul_orig(x, y); assert(f_eqeq_p(r, f_mul(LONG2NUM(x), LONG2NUM(y)))); return r; }
static VALUE float_to_r(VALUE self) { VALUE f, n; float_decode_internal(self, &f, &n); return f_mul(f, f_expt(INT2FIX(FLT_RADIX), n)); }
static VALUE nurat_round(VALUE self) { get_dat1(self); if (f_negative_p(dat->num)) { VALUE num, den; num = f_negate(dat->num); num = f_add(f_mul(num, TWO), dat->den); den = f_mul(dat->den, TWO); return f_negate(f_idiv(num, den)); } else { VALUE num = f_add(f_mul(dat->num, TWO), dat->den); VALUE den = f_mul(dat->den, TWO); return f_idiv(num, den); } }
static VALUE f_complex_polar(VALUE klass, VALUE x, VALUE y) { assert(!k_complex_p(x)); assert(!k_complex_p(y)); if (f_zero_p(x) || f_zero_p(y)) { if (canonicalization) return x; return nucomp_s_new_internal(klass, x, RFLOAT_0); } if (RB_FLOAT_TYPE_P(y)) { const double arg = RFLOAT_VALUE(y); if (arg == M_PI) { x = f_negate(x); if (canonicalization) return x; y = RFLOAT_0; } else if (arg == M_PI_2) { y = x; x = RFLOAT_0; } else if (arg == M_PI_2+M_PI) { y = f_negate(x); x = RFLOAT_0; } else if (RB_FLOAT_TYPE_P(x)) { const double abs = RFLOAT_VALUE(x); const double real = abs * cos(arg), imag = abs * sin(arg); x = DBL2NUM(real); if (canonicalization && imag == 0.0) return x; y = DBL2NUM(imag); } else { x = f_mul(x, DBL2NUM(cos(arg))); y = f_mul(y, DBL2NUM(sin(arg))); if (canonicalization && f_zero_p(y)) return x; } return nucomp_s_new_internal(klass, x, y); } return nucomp_s_canonicalize_internal(klass, f_mul(x, m_cos(y)), f_mul(x, m_sin(y))); }
static VALUE safe_mul(VALUE a, VALUE b, int az, int bz) { double v; if (!az && bz && RB_FLOAT_TYPE_P(a) && (v = RFLOAT_VALUE(a), !isnan(v))) { a = signbit(v) ? DBL2NUM(-1.0) : DBL2NUM(1.0); } if (!bz && az && RB_FLOAT_TYPE_P(b) && (v = RFLOAT_VALUE(b), !isnan(v))) { b = signbit(v) ? DBL2NUM(-1.0) : DBL2NUM(1.0); } return f_mul(a, b); }
inline static VALUE f_muldiv(VALUE self, VALUE anum, VALUE aden, VALUE bnum, VALUE bden, int k) { VALUE num, den; if (k == '/') { VALUE t; if (f_negative_p(bnum)) { anum = f_negate(anum); bnum = f_negate(bnum); } t = bnum; bnum = bden; bden = t; } if (FIXNUM_P(anum) && FIXNUM_P(aden) && FIXNUM_P(bnum) && FIXNUM_P(bden)) { long an = FIX2LONG(anum); long ad = FIX2LONG(aden); long bn = FIX2LONG(bnum); long bd = FIX2LONG(bden); long g1 = i_gcd(an, bd); long g2 = i_gcd(ad, bn); num = f_imul(an / g1, bn / g2); den = f_imul(ad / g2, bd / g1); } else { VALUE g1 = f_gcd(anum, bden); VALUE g2 = f_gcd(aden, bnum); num = f_mul(f_idiv(anum, g1), f_idiv(bnum, g2)); den = f_mul(f_idiv(aden, g2), f_idiv(bden, g1)); } return f_rational_new_no_reduce2(CLASS_OF(self), num, den); }
static VALUE nurat_round(VALUE self, SEL sel) { VALUE num, den, neg; get_dat1(self); num = dat->num; den = dat->den; neg = f_negative_p(num); if (neg) num = f_negate(num); num = f_add(f_mul(num, TWO), den); den = f_mul(den, TWO); num = f_idiv(num, den); if (neg) num = f_negate(num); return num; }
static VALUE nurat_cmp(VALUE self, VALUE other) { switch (TYPE(other)) { case T_FIXNUM: case T_BIGNUM: { get_dat1(self); if (FIXNUM_P(dat->den) && FIX2LONG(dat->den) == 1) return f_cmp(dat->num, other); else return f_cmp(self, f_rational_new_bang1(CLASS_OF(self), other)); } case T_FLOAT: return f_cmp(f_to_f(self), other); case T_RATIONAL: { VALUE num1, num2; get_dat2(self, other); if (FIXNUM_P(adat->num) && FIXNUM_P(adat->den) && FIXNUM_P(bdat->num) && FIXNUM_P(bdat->den)) { num1 = f_imul(FIX2LONG(adat->num), FIX2LONG(bdat->den)); num2 = f_imul(FIX2LONG(bdat->num), FIX2LONG(adat->den)); } else { num1 = f_mul(adat->num, bdat->den); num2 = f_mul(bdat->num, adat->den); } return f_cmp(f_sub(num1, num2), ZERO); } default: return rb_num_coerce_bin(self, other, id_cmp); } }
/* * call-seq: * flt.to_r -> rational * * Returns the value as a rational. * * NOTE: 0.3.to_r isn't the same as '0.3'.to_r. The latter is * equivalent to '3/10'.to_r, but the former isn't so. * * For example: * * 2.0.to_r #=> (2/1) * 2.5.to_r #=> (5/2) * -0.75.to_r #=> (-3/4) * 0.0.to_r #=> (0/1) */ static VALUE float_to_r(VALUE self, SEL sel) { VALUE f, n; float_decode_internal(self, &f, &n); #if FLT_RADIX == 2 { long ln = FIX2LONG(n); if (ln == 0) return f_to_r(f); if (ln > 0) return f_to_r(f_lshift(f, n)); ln = -ln; return rb_rational_new2(f, f_lshift(ONE, INT2FIX(ln))); } #else return f_to_r(f_mul(f, f_expt(INT2FIX(FLT_RADIX), n))); #endif }
/* * 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, '*'); }
/* * 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 */ } if (k_complex_p(other)) { VALUE r, theta, nr, ntheta; get_dat1(other); r = f_abs(self); theta = f_arg(self); nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)), f_mul(dat->imag, theta))); ntheta = f_add(f_mul(theta, dat->real), f_mul(dat->imag, m_log_bang(r))); return f_complex_polar(CLASS_OF(self), nr, ntheta); } if (k_fixnum_p(other)) { if (f_gt_p(other, ZERO)) { VALUE x, z; long n; x = self; z = x; n = FIX2LONG(other) - 1; while (n) { long q, r; while (1) { get_dat1(x); q = n / 2; r = n % 2; if (r) break; x = nucomp_s_new_internal(CLASS_OF(self), f_sub(f_mul(dat->real, dat->real), f_mul(dat->imag, dat->imag)), f_mul(f_mul(TWO, dat->real), dat->imag)); n = q; } z = f_mul(z, x); n--; } return z; } return f_expt(f_reciprocal(self), f_negate(other)); } if (k_numeric_p(other) && f_real_p(other)) { VALUE r, theta; if (k_bignum_p(other)) rb_warn("in a**b, b may be too big"); r = f_abs(self); theta = f_arg(self); 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 nurat_mod(VALUE self, VALUE other) { VALUE val = f_floor(f_div(self, other)); return f_sub(self, f_mul(other, val)); }
static VALUE nurat_divmod(VALUE self, VALUE other) { VALUE val = f_floor(f_div(self, other)); return rb_assoc_new(val, f_sub(self, f_mul(other, val))); }
/* * call-seq: * num.abs2 -> real * * Returns square of self. */ static VALUE numeric_abs2(VALUE self) { return f_mul(self, self); }
static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass) { VALUE a1, a2, backref; rb_scan_args(argc, argv, "11", &a1, &a2); if (NIL_P(a1) || (argc == 2 && NIL_P(a2))) rb_raise(rb_eTypeError, "can't convert nil into Complex"); backref = rb_backref_get(); rb_match_busy(backref); if (RB_TYPE_P(a1, T_STRING)) { a1 = string_to_c_strict(a1); } if (RB_TYPE_P(a2, T_STRING)) { a2 = string_to_c_strict(a2); } rb_backref_set(backref); if (RB_TYPE_P(a1, T_COMPLEX)) { { get_dat1(a1); if (k_exact_zero_p(dat->imag)) a1 = dat->real; } } if (RB_TYPE_P(a2, T_COMPLEX)) { { get_dat1(a2); if (k_exact_zero_p(dat->imag)) a2 = dat->real; } } if (RB_TYPE_P(a1, T_COMPLEX)) { if (argc == 1 || (k_exact_zero_p(a2))) return a1; } if (argc == 1) { if (k_numeric_p(a1) && !f_real_p(a1)) return a1; /* should raise exception for consistency */ if (!k_numeric_p(a1)) return rb_convert_type(a1, T_COMPLEX, "Complex", "to_c"); } else { if ((k_numeric_p(a1) && k_numeric_p(a2)) && (!f_real_p(a1) || !f_real_p(a2))) return f_add(a1, f_mul(a2, f_complex_new_bang2(rb_cComplex, ZERO, ONE))); } { VALUE argv2[2]; argv2[0] = a1; argv2[1] = a2; return nucomp_s_new(argc, argv2, klass); } }
static VALUE nurat_rem(VALUE self, VALUE other) { VALUE val = f_truncate(f_div(self, other)); return f_sub(self, f_mul(other, val)); }
/* :nodoc: */ static VALUE nurat_quotrem(VALUE self, VALUE other) { VALUE val = f_truncate(f_div(self, other)); return rb_assoc_new(val, f_sub(self, f_mul(other, val))); }
static VALUE string_to_r_internal(VALUE self) { VALUE s, m; s = self; if (RSTRING_LEN(s) == 0) return rb_assoc_new(Qnil, self); m = f_match(rat_pat, s); if (!NIL_P(m)) { VALUE v, ifp, exp, ip, fp; VALUE si = f_aref(m, INT2FIX(1)); VALUE nu = f_aref(m, INT2FIX(2)); VALUE de = f_aref(m, INT2FIX(3)); VALUE re = f_post_match(m); { VALUE a; a = f_split(nu, an_e_pat); ifp = RARRAY_PTR(a)[0]; if (RARRAY_LEN(a) != 2) exp = Qnil; else exp = RARRAY_PTR(a)[1]; a = f_split(ifp, a_dot_pat); ip = RARRAY_PTR(a)[0]; if (RARRAY_LEN(a) != 2) fp = Qnil; else fp = RARRAY_PTR(a)[1]; } v = rb_rational_new1(f_to_i(ip)); if (!NIL_P(fp)) { char *p = StringValuePtr(fp); long count = 0; VALUE l; while (*p) { if (rb_isdigit(*p)) count++; p++; } l = f_expt(INT2FIX(10), LONG2NUM(count)); v = f_mul(v, l); v = f_add(v, f_to_i(fp)); v = f_div(v, l); } if (!NIL_P(si) && *StringValuePtr(si) == '-') v = f_negate(v); if (!NIL_P(exp)) v = f_mul(v, f_expt(INT2FIX(10), f_to_i(exp))); #if 0 if (!NIL_P(de) && (!NIL_P(fp) || !NIL_P(exp))) return rb_assoc_new(v, rb_usascii_str_new2("dummy")); #endif if (!NIL_P(de)) v = f_div(v, f_to_i(de)); return rb_assoc_new(v, re); } return rb_assoc_new(Qnil, self); }