Exemple #1
0
/*
 * 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, '/');
    }
}
Exemple #2
0
inline static VALUE
f_gcd(VALUE x, VALUE y)
{
    VALUE z;

    if (FIXNUM_P(x) && FIXNUM_P(y))
	return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));

    if (f_negative_p(x))
	x = f_negate(x);
    if (f_negative_p(y))
	y = f_negate(y);

    if (f_zero_p(x))
	return y;
    if (f_zero_p(y))
	return x;

    for (;;) {
	if (FIXNUM_P(x)) {
	    if (FIX2LONG(x) == 0)
		return y;
	    if (FIXNUM_P(y))
		return LONG2NUM(i_gcd(FIX2LONG(x), FIX2LONG(y)));
	}
	z = x;
	x = f_mod(y, x);
	y = z;
    }
    /* NOTREACHED */
}
Exemple #3
0
/*
 * 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, '*');
}
Exemple #4
0
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, '/');
    }
}
Exemple #5
0
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));
}
Exemple #6
0
inline static VALUE
f_gcd(VALUE x, VALUE y)
{
    VALUE r = f_gcd_orig(x, y);
    if (f_nonzero_p(r)) {
	assert(f_zero_p(f_mod(x, r)));
	assert(f_zero_p(f_mod(y, r)));
    }
    return r;
}
Exemple #7
0
inline static VALUE
f_rational_new_bang2(VALUE klass, VALUE x, VALUE y)
{
    assert(!f_negative_p(y));
    assert(!f_zero_p(y));
    return nurat_s_new_internal(klass, x, y);
}
Exemple #8
0
/*
 * call-seq:
 *    rat.fdiv(numeric)  ->  float
 *
 * Performs division and returns the value as a float.
 *
 * For example:
 *
 *    Rational(2, 3).fdiv(1)       #=> 0.6666666666666666
 *    Rational(2, 3).fdiv(0.5)     #=> 1.3333333333333333
 *    Rational(2).fdiv(3)          #=> 0.6666666666666666
 */
static VALUE
nurat_fdiv(VALUE self, SEL sel, VALUE other)
{
    if (f_zero_p(other))
	return f_div(self, f_to_f(other));
    return f_to_f(f_div(self, other));
}
Exemple #9
0
static VALUE
nurat_to_f(VALUE self)
{
    VALUE num, den;
    int minus = 0;
    long nl, dl, ml, ne, de;
    int e;
    double f;

    {
	get_dat1(self);

	if (f_zero_p(dat->num))
	    return rb_float_new(0.0);

	num = dat->num;
	den = dat->den;
    }

    if (f_negative_p(num)) {
	num = f_negate(num);
	minus = 1;
    }

    nl = i_ilog2(num);
    dl = i_ilog2(den);
    ml = (long)(log(DBL_MAX) / log(2.0) - 1); /* should be a static */

    ne = 0;
    if (nl > ml) {
	ne = nl - ml;
	num = f_rshift(num, LONG2NUM(ne));
    }

    de = 0;
    if (dl > ml) {
	de = dl - ml;
	den = f_rshift(den, LONG2NUM(de));
    }

    e = (int)(ne - de);

    if ((e > DBL_MAX_EXP) || (e < DBL_MIN_EXP)) {
	rb_warning("%s out of Float range", rb_obj_classname(self));
	return rb_float_new(e > 0 ? HUGE_VAL : 0.0);
    }

    f = NUM2DBL(num) / NUM2DBL(den);
    if (minus)
	f = -f;
    f = ldexp(f, e);

    if (isinf(f) || isnan(f))
	rb_warning("%s out of Float range", rb_obj_classname(self));

    return rb_float_new(f);
}
Exemple #10
0
/*
 * call-seq:
 *    cmp.abs        ->  real
 *    cmp.magnitude  ->  real
 *
 * Returns the absolute part of its polar form.
 *
 *    Complex(-1).abs         #=> 1
 *    Complex(3.0, -4.0).abs  #=> 5.0
 */
static VALUE
nucomp_abs(VALUE self)
{
    get_dat1(self);

    if (f_zero_p(dat->real)) {
	VALUE a = f_abs(dat->imag);
	if (k_float_p(dat->real) && !k_float_p(dat->imag))
	    a = f_to_f(a);
	return a;
    }
    if (f_zero_p(dat->imag)) {
	VALUE a = f_abs(dat->real);
	if (!k_float_p(dat->real) && k_float_p(dat->imag))
	    a = f_to_f(a);
	return a;
    }
    return m_hypot(dat->real, dat->imag);
}
Exemple #11
0
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)));
}
Exemple #12
0
static VALUE
nurat_marshal_load(VALUE self, VALUE a)
{
    get_dat1(self);
    dat->num = RARRAY_AT(a, 0);
    dat->den = RARRAY_AT(a, 1);

    if (f_zero_p(dat->den))
	rb_raise(rb_eZeroDivError, "devided by zero");

    return self;
}
Exemple #13
0
/* :nodoc: */
static VALUE
nurat_marshal_load(VALUE self, SEL sel, VALUE a)
{
    get_dat1(self);
    dat->num = RARRAY_PTR(a)[0];
    dat->den = RARRAY_PTR(a)[1];
    rb_copy_generic_ivar(self, a);

    if (f_zero_p(dat->den))
	rb_raise_zerodiv();

    return self;
}
Exemple #14
0
inline static VALUE
nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
{
#ifdef CANON
#define CL_CANON
#ifdef CL_CANON
    if (f_zero_p(imag) && k_exact_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));
    }
}
Exemple #15
0
/*
 * call-seq:
 *    rat == object  ->  true or false
 *
 * Returns true if rat equals object numerically.
 *
 * For example:
 *
 *    Rational(2, 3)  == Rational(2, 3)   #=> true
 *    Rational(5)     == 5                #=> true
 *    Rational(0)     == 0.0              #=> true
 *    Rational('1/3') == 0.33             #=> false
 *    Rational('1/2') == '1/2'            #=> false
 */
static VALUE
nurat_eqeq_p(VALUE self, SEL sel, VALUE other)
{
    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
	{
	    get_dat1(self);

	    if (f_zero_p(dat->num) && f_zero_p(other))
		return Qtrue;

	    if (!FIXNUM_P(dat->den))
		return Qfalse;
	    if (FIX2LONG(dat->den) != 1)
		return Qfalse;
	    if (f_eqeq_p(dat->num, other))
		return Qtrue;
	    return Qfalse;
	}
      case T_FLOAT:
	return f_eqeq_p(f_to_f(self), other);
      case T_RATIONAL:
	{
	    get_dat2(self, other);

	    if (f_zero_p(adat->num) && f_zero_p(bdat->num))
		return Qtrue;

	    return f_boolcast(f_eqeq_p(adat->num, bdat->num) &&
			      f_eqeq_p(adat->den, bdat->den));
	}
      default:
	return f_eqeq_p(other, self);
    }
}
Exemple #16
0
/*
 * call-seq:
 *    cmp == object  ->  true or false
 *
 * Returns true if cmp equals object numerically.
 *
 *    Complex(2, 3)  == Complex(2, 3)   #=> true
 *    Complex(5)     == 5               #=> true
 *    Complex(0)     == 0.0             #=> true
 *    Complex('1/3') == 0.33            #=> false
 *    Complex('1/2') == '1/2'           #=> false
 */
static VALUE
nucomp_eqeq_p(VALUE self, VALUE other)
{
    if (k_complex_p(other)) {
	get_dat2(self, other);

	return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
			  f_eqeq_p(adat->imag, bdat->imag));
    }
    if (k_numeric_p(other) && f_real_p(other)) {
	get_dat1(self);

	return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
    }
    return f_eqeq_p(other, self);
}
Exemple #17
0
static VALUE
nurat_expt(VALUE self, VALUE other)
{
    if (f_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; /* good? */
    }

    switch (TYPE(other)) {
      case T_FIXNUM:
      case T_BIGNUM:
	{
	    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_FLOAT:
      case T_RATIONAL:
	return f_expt(f_to_f(self), other);
      default:
	return rb_num_coerce_bin(self, other, id_expt);
    }
}
Exemple #18
0
static VALUE
nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
{
    VALUE a1, a2, backref;

    rb_scan_args(argc, argv, "11", &a1, &a2);

    backref = rb_backref_get();
    rb_match_busy(backref);

    switch (TYPE(a1)) {
      case T_FIXNUM:
      case T_BIGNUM:
      case T_FLOAT:
	break;
      case T_STRING:
	a1 = string_to_c_strict(a1);
	break;
    }

    switch (TYPE(a2)) {
      case T_FIXNUM:
      case T_BIGNUM:
      case T_FLOAT:
	break;
      case T_STRING:
	a2 = string_to_c_strict(a2);
	break;
    }

    rb_backref_set(backref);

    switch (TYPE(a1)) {
      case T_COMPLEX:
	{
	    get_dat1(a1);

	    if (k_exact_p(dat->imag) && f_zero_p(dat->imag))
		a1 = dat->real;
	}
    }

    switch (TYPE(a2)) {
      case T_COMPLEX:
	{
	    get_dat1(a2);

	    if (k_exact_p(dat->imag) && f_zero_p(dat->imag))
		a2 = dat->real;
	}
    }

    switch (TYPE(a1)) {
      case T_COMPLEX:
	if (argc == 1 || (k_exact_p(a2) && f_zero_p(a2)))
	    return a1;
    }

    if (argc == 1) {
	if (k_numeric_p(a1) && !f_real_p(a1))
	    return a1;
    }
    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);
    }
}
Exemple #19
0
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);
}
Exemple #20
0
static VALUE
nurat_s_convert(int argc, VALUE *argv, VALUE klass)
{
    VALUE a1, a2, backref;

    rb_scan_args(argc, argv, "11", &a1, &a2);

    switch (TYPE(a1)) {
      case T_COMPLEX:
	if (k_exact_p(RCOMPLEX(a1)->imag) && f_zero_p(RCOMPLEX(a1)->imag))
	    a1 = RCOMPLEX(a1)->real;
    }

    switch (TYPE(a2)) {
      case T_COMPLEX:
	if (k_exact_p(RCOMPLEX(a2)->imag) && f_zero_p(RCOMPLEX(a2)->imag))
	    a2 = RCOMPLEX(a2)->real;
    }

    backref = rb_backref_get();
    rb_match_busy(backref);

    switch (TYPE(a1)) {
      case T_FIXNUM:
      case T_BIGNUM:
	break;
      case T_FLOAT:
	a1 = f_to_r(a1);
	break;
      case T_STRING:
	a1 = string_to_r_strict(a1);
	break;
    }

    switch (TYPE(a2)) {
      case T_FIXNUM:
      case T_BIGNUM:
	break;
      case T_FLOAT:
	a2 = f_to_r(a2);
	break;
      case T_STRING:
	a2 = string_to_r_strict(a2);
	break;
    }

    rb_backref_set(backref);

    switch (TYPE(a1)) {
      case T_RATIONAL:
	if (argc == 1 || (k_exact_p(a2) && f_one_p(a2)))
	    return a1;
    }

    if (argc == 1) {
	if (k_numeric_p(a1) && !f_integer_p(a1))
	    return a1;
    }
    else {
	if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
	    (!f_integer_p(a1) || !f_integer_p(a2)))
	    return f_div(a1, a2);
    }

    {
	VALUE argv2[2];
	argv2[0] = a1;
	argv2[1] = a2;
	return nurat_s_new(argc, argv2, klass);
    }
}
Exemple #21
0
static VALUE
nurat_s_convert(int argc, VALUE *argv, VALUE klass)
{
    VALUE a1, a2;

    if (rb_scan_args(argc, argv, "02", &a1, &a2) == 1) {
	a2 = ONE;
    }

    switch (TYPE(a1)) {
      case T_COMPLEX:
	if (k_float_p(RCOMPLEX(a1)->image) || !f_zero_p(RCOMPLEX(a1)->image)) {
	    VALUE s = f_to_s(a1);
	    rb_raise(rb_eRangeError, "can't accept %s",
		     StringValuePtr(s));
	}
	a1 = RCOMPLEX(a1)->real;
    }

    switch (TYPE(a2)) {
      case T_COMPLEX:
	if (k_float_p(RCOMPLEX(a2)->image) || !f_zero_p(RCOMPLEX(a2)->image)) {
	    VALUE s = f_to_s(a2);
	    rb_raise(rb_eRangeError, "can't accept %s",
		     StringValuePtr(s));
	}
	a2 = RCOMPLEX(a2)->real;
    }

    switch (TYPE(a1)) {
      case T_FIXNUM:
      case T_BIGNUM:
	break;
      case T_FLOAT:
	a1 = f_to_r(a1);
	break;
      case T_STRING:
	a1 = string_to_r_strict(a1);
	break;
    }

    switch (TYPE(a2)) {
      case T_FIXNUM:
      case T_BIGNUM:
	break;
      case T_FLOAT:
	a2 = f_to_r(a2);
	break;
      case T_STRING:
	a2 = string_to_r_strict(a2);
	break;
    }

    switch (TYPE(a1)) {
      case T_RATIONAL:
	if (NIL_P(a2) || f_zero_p(a2))
	    return a1;
	else
	    return f_div(a1, a2);
    }

    switch (TYPE(a2)) {
      case T_RATIONAL:
	return f_div(a1, a2);
    }

    return nurat_s_new(klass, a1, a2);
}