static VALUE rb_hack_rshift (VALUE x, VALUE y) { if ( rb_obj_is_carray(y) ) { #if RUBY_VERSION_CODE >= 190 return rb_num_coerce_bin(x, y, rb_intern(">>")); #else return rb_num_coerce_bin(x, y); #endif } else { return rb_funcall(x, id___rshift__, 1, y); } }
/* * call-seq: * onum / integer -> oranumber * onum / numeric -> numeric * * Returns the result of dividing <i>onum</i> by <i>other</i>. */ static VALUE onum_div(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; boolean is_zero; switch (rboci8_type(rhs)) { case T_FIXNUM: if (rhs == INT2FIX(0)) { rb_num_zerodiv(); } case T_BIGNUM: if (set_oci_number_from_num(&n, rhs, 0, errhp)) { chkerr(OCINumberDiv(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); } break; case RBOCI8_T_ORANUMBER: chkerr(OCINumberIsZero(errhp, _NUMBER(rhs), &is_zero)); if (is_zero) { rb_num_zerodiv(); } chkerr(OCINumberDiv(errhp, _NUMBER(lhs), _NUMBER(rhs), &r)); return oci8_make_ocinumber(&r, errhp); case T_FLOAT: return rb_funcall(onum_to_f(lhs), oci8_id_div_op, 1, rhs); case RBOCI8_T_RATIONAL: return rb_funcall(onum_to_r(lhs), oci8_id_div_op, 1, rhs); case RBOCI8_T_BIGDECIMAL: return rb_funcall(onum_to_d(lhs), oci8_id_div_op, 1, rhs); } return rb_num_coerce_bin(lhs, rhs, oci8_id_div_op); }
/* * call-seq: * onum * other -> number * * Returns the product of <i>onum</i> and <i>other</i>. */ static VALUE onum_mul(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; switch (rboci8_type(rhs)) { case T_FIXNUM: case T_BIGNUM: if (set_oci_number_from_num(&n, rhs, 0, errhp)) { chkerr(OCINumberMul(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); } break; case RBOCI8_T_ORANUMBER: chkerr(OCINumberMul(errhp, _NUMBER(lhs), _NUMBER(rhs), &r)); return oci8_make_ocinumber(&r, errhp); case T_FLOAT: return rb_funcall(onum_to_f(lhs), oci8_id_mul_op, 1, rhs); case RBOCI8_T_RATIONAL: return rb_funcall(onum_to_r(lhs), oci8_id_mul_op, 1, rhs); case RBOCI8_T_BIGDECIMAL: return rb_funcall(onum_to_d(lhs), oci8_id_mul_op, 1, rhs); } return rb_num_coerce_bin(lhs, rhs, oci8_id_mul_op); }
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: * 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, '*'); } }
/* * 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, '*'); }
/* * call-seq: * rat / numeric -> numeric_result * rat.quo(numeric) -> numeric_result * * Performs division. * * For example: * * Rational(2, 3) / Rational(2, 3) #=> (1/1) * Rational(900) / Rational(1) #=> (900/1) * Rational(-2, 9) / Rational(-9, 2) #=> (4/81) * Rational(9, 8) / 4 #=> (9/32) * Rational(20, 9) / 9.8 #=> 0.22675736961451246 */ static VALUE nurat_div(VALUE self, SEL sel, VALUE other) { switch (TYPE(other)) { case T_FIXNUM: case T_BIGNUM: if (f_zero_p(other)) rb_raise_zerodiv(); { get_dat1(self); return f_muldiv(self, dat->num, dat->den, other, ONE, '/'); } case T_FLOAT: return rb_funcall(f_to_f(self), '/', 1, other); case T_RATIONAL: if (f_zero_p(other)) rb_raise_zerodiv(); { get_dat2(self, other); if (f_one_p(self)) return f_rational_new_no_reduce2(CLASS_OF(self), bdat->den, bdat->num); return f_muldiv(self, adat->num, adat->den, bdat->num, bdat->den, '/'); } default: return rb_num_coerce_bin(self, other, '/'); } }
/* * Using the Euclidean Algorithm (division-based): * http://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations * * In ruby: * a = self * while b != 0 * a, b = b, a % b * end * return a */ VALUE rb_big_gcd_euclidean_division(VALUE a, VALUE b) { VALUE temp; /* borrowed from bignum.c, rb_big_modulo() */ switch (TYPE(b)) { case T_FIXNUM: b = rb_int2big(FIX2LONG(b)); break; case T_BIGNUM: break; default: return rb_num_coerce_bin(a, b, '%'); } while ((TYPE(b) == T_BIGNUM && !rb_bigzero_p(b)) || (TYPE(b) == T_FIXNUM && FIX2LONG(b) != 0)) { if (TYPE(b) == T_BIGNUM) { temp = rb_big_clone(b); } else { temp = b; } //b = rb_big_modulo(a, b); b = rb_funcall(a, mod_id, 1, b); a = temp; } return a; }
static VALUE nurat_div(VALUE self, VALUE other) { switch (TYPE(other)) { case T_FIXNUM: case T_BIGNUM: if (f_zero_p(other)) rb_raise(rb_eZeroDivError, "devided by zero"); { get_dat1(self); return f_muldiv(self, dat->num, dat->den, other, ONE, '/'); } case T_FLOAT: return rb_funcall(f_to_f(self), '/', 1, other); case T_RATIONAL: if (f_zero_p(other)) rb_raise(rb_eZeroDivError, "devided by zero"); { get_dat2(self, other); return f_muldiv(self, adat->num, adat->den, bdat->num, bdat->den, '/'); } default: return rb_num_coerce_bin(self, other, '/'); } }
static VALUE rb_hack_xor (VALUE x, VALUE y) { if ( rb_obj_is_carray(y) ) { if ( rb_ca_is_boolean_type(y) ) { return rb_funcall(y, rb_intern("bit_xor"), 1, x); } else { #if RUBY_VERSION_CODE >= 190 return rb_num_coerce_bin(x, y, '^'); #else return rb_num_coerce_bin(x, y); #endif } } else { return rb_funcall(x, id___xor__, 1, 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: * onum ** other -> oranumber * * Raises <i>onum</i> the <i>other</i> power. */ static VALUE onum_power(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; if (FIXNUM_P(rhs)) { chkerr(OCINumberIntPower(errhp, _NUMBER(lhs), FIX2INT(rhs), &r)); } else { /* change to OCINumber */ if (!set_oci_number_from_num(&n, rhs, 0, errhp)) return rb_num_coerce_bin(lhs, rhs, id_power); chkerr(OCINumberPower(errhp, _NUMBER(lhs), &n, &r)); } return oci8_make_ocinumber(&r, errhp); }
/* * call-seq: * rat ** numeric -> numeric_result * * Performs exponentiation. * * For example: * * Rational(2) ** Rational(3) #=> (8/1) * Rational(10) ** -2 #=> (1/100) * Rational(10) ** -2.0 #=> 0.01 * Rational(-4) ** Rational(1,2) #=> (1.2246063538223773e-16+2.0i) * Rational(1, 2) ** 0 #=> (1/1) * Rational(1, 2) ** 0.0 #=> 1.0 */ static VALUE nurat_expt(VALUE self, SEL sel, VALUE other) { if (k_exact_zero_p(other)) return f_rational_new_bang1(CLASS_OF(self), ONE); if (k_rational_p(other)) { get_dat1(other); if (f_one_p(dat->den)) other = dat->num; /* c14n */ } switch (TYPE(other)) { case T_FIXNUM: { VALUE num, den; get_dat1(self); switch (FIX2INT(f_cmp(other, ZERO))) { case 1: num = f_expt(dat->num, other); den = f_expt(dat->den, other); break; case -1: num = f_expt(dat->den, f_negate(other)); den = f_expt(dat->num, f_negate(other)); break; default: num = ONE; den = ONE; break; } return f_rational_new2(CLASS_OF(self), num, den); } case T_BIGNUM: rb_warn("in a**b, b may be too big"); /* fall through */ case T_FLOAT: case T_RATIONAL: return f_expt(f_to_f(self), other); default: return rb_num_coerce_bin(self, other, id_expt); } }
/* * call-seq: * onum % other -> oranumber * * Returns the modulo after division of <i>onum</i> by <i>other</i>. */ static VALUE onum_mod(VALUE lhs, VALUE rhs) { OCIError *errhp = oci8_errhp; OCINumber n; OCINumber r; boolean is_zero; /* change to OCINumber */ if (!set_oci_number_from_num(&n, rhs, 0, errhp)) return rb_num_coerce_bin(lhs, rhs, '%'); /* check whether argument is not zero. */ chkerr(OCINumberIsZero(errhp, &n, &is_zero)); if (is_zero) rb_num_zerodiv(); /* modulo */ chkerr(OCINumberMod(errhp, _NUMBER(lhs), &n, &r)); return oci8_make_ocinumber(&r, errhp); }
static VALUE nucomp_sub(VALUE self, VALUE other) { if (k_complex_p(other)) { VALUE real, imag; get_dat2(self, other); real = f_sub(adat->real, bdat->real); imag = f_sub(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), f_sub(dat->real, other), dat->imag); } return rb_num_coerce_bin(self, other, '-'); }
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); }
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: * 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 nucomp_expt(VALUE self, VALUE other) { if (k_exact_p(other) && f_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); /* good? */ 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->imag; 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; x = self; z = x; n = f_sub(other, ONE); while (f_nonzero_p(n)) { VALUE a; while (a = f_divmod(n, TWO), f_zero_p(RARRAY_PTR(a)[1])) { get_dat1(x); x = f_complex_new2(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 = RARRAY_PTR(a)[0]; } z = f_mul(z, x); n = f_sub(n, ONE); } return z; } return f_expt(f_div(f_to_r(ONE), self), f_negate(other)); } if (k_numeric_p(other) && f_real_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 numeric_spec_rb_num_coerce_bin(VALUE self, VALUE x, VALUE y, VALUE op) { return rb_num_coerce_bin(x, y, SYM2ID(op)); }