18#if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
29#include "internal/gc.h"
35#define ZERO INT2FIX(0)
39#define GMP_GCD_DIGITS 1
41#define INT_ZERO_P(x) (FIXNUM_P(x) ? FIXNUM_ZERO_P(x) : rb_bigzero_p(x))
45static ID id_abs, id_integer_p,
51#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
52#define f_inspect rb_inspect
53#define f_to_s rb_obj_as_string
108 if (y ==
ONE)
return x;
111 if (x ==
ONE)
return y;
120 if (
FIXNUM_P(y) && FIXNUM_ZERO_P(y))
166#define f_expt10(x) rb_int_pow(INT2FIX(10), x)
172 return FIXNUM_ZERO_P(x);
177 return FIXNUM_ZERO_P(
num);
182#define f_nonzero_p(x) (!f_zero_p(x))
200f_minus_one_p(
VALUE x)
238 return RB_FLOAT_TYPE_P(x);
247#define k_exact_p(x) (!k_float_p(x))
248#define k_inexact_p(x) k_float_p(x)
250#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
251#define k_exact_one_p(x) (k_exact_p(x) && f_one_p(x))
266 mpz_import(mx, BIGNUM_LEN(x), -1,
sizeof(
BDIGIT), 0, nails, BIGNUM_DIGITS(x));
267 mpz_import(my, BIGNUM_LEN(y), -1,
sizeof(
BDIGIT), 0, nails, BIGNUM_DIGITS(y));
276 mpz_export(BIGNUM_DIGITS(z), &
count, -1,
sizeof(
BDIGIT), 0, nails, mz);
285#define f_gcd f_gcd_orig
291 unsigned long u, v,
t;
304 u = (
unsigned long)x;
305 v = (
unsigned long)y;
306 for (shift = 0; ((u | v) & 1) == 0; ++shift) {
326 return (
long)(u << shift);
337 if (INT_NEGATIVE_P(x))
339 if (INT_NEGATIVE_P(y))
349 if (FIXNUM_ZERO_P(x))
364 return f_gcd_normal(x, y);
372 size_t xn = BIGNUM_LEN(x);
373 size_t yn = BIGNUM_LEN(y);
375 return rb_gcd_gmp(x, y);
378 return f_gcd_normal(x, y);
387 VALUE r = f_gcd_orig(x, y);
405 struct RRational *dat = RRATIONAL(x)
407#define get_dat2(x,y) \
408 struct RRational *adat = RRATIONAL(x), *bdat = RRATIONAL(y)
416 RATIONAL_SET_DEN((
VALUE)obj, den);
423nurat_s_alloc(
VALUE klass)
425 return nurat_s_new_internal(klass,
ZERO,
ONE);
431 return nurat_s_new_internal(klass, x,
ONE);
438 if (!k_numeric_p(
num) || !f_integer_p(
num))
446 nurat_int_check(
num);
447 if (!k_integer_p(
num))
457 if (INT_NEGATIVE_P(*den)) {
470 if (*x ==
ONE || *y ==
ONE)
return;
479 nurat_canonicalize(&
num, &den);
480 nurat_reduce(&
num, &den);
482 return nurat_s_new_internal(klass,
num, den);
488 nurat_canonicalize(&
num, &den);
490 return nurat_s_new_internal(klass,
num, den);
498 return nurat_s_canonicalize_internal(klass, x, y);
506 return nurat_s_canonicalize_internal_no_reduce(klass, x, y);
576nurat_numerator(
VALUE self)
594nurat_denominator(
VALUE self)
616#define f_imul f_imul_orig
620f_imul(
long a,
long b)
624 if (a == 0 || b == 0)
642f_imul(
long x,
long y)
644 VALUE r = f_imul_orig(x, y);
661 long ig = i_gcd(ad, bd);
664 VALUE a = f_imul(an, bd / ig);
665 VALUE b = f_imul(bn, ad / ig);
681 VALUE g = f_gcd(aden, bden);
700 double c = k ==
'+' ? a + b : a - b;
703 return f_rational_new_no_reduce2(
CLASS_OF(self),
num, den);
706static double nurat_to_double(
VALUE self);
726 return f_rational_new_no_reduce2(
CLASS_OF(self),
731 else if (RB_FLOAT_TYPE_P(other)) {
738 return f_addsub(self,
739 adat->num, adat->den,
740 bdat->num, bdat->den,
'+');
767 return f_rational_new_no_reduce2(
CLASS_OF(self),
772 else if (RB_FLOAT_TYPE_P(other)) {
779 return f_addsub(self,
780 adat->num, adat->den,
781 bdat->num, bdat->den,
'-');
797 if (RB_FLOAT_TYPE_P(anum) || RB_FLOAT_TYPE_P(aden) ||
798 RB_FLOAT_TYPE_P(bnum) || RB_FLOAT_TYPE_P(bden)) {
801 double x = (an * bn) / (ad * bd);
813 if (INT_NEGATIVE_P(bnum)) {
828 long g1 = i_gcd(an, bd);
829 long g2 = i_gcd(ad, bn);
831 num = f_imul(an / g1, bn / g2);
832 den = f_imul(ad / g2, bd / g1);
835 VALUE g1 = f_gcd(anum, bden);
836 VALUE g2 = f_gcd(aden, bnum);
841 return f_rational_new_no_reduce2(
CLASS_OF(self),
num, den);
863 return f_muldiv(self,
868 else if (RB_FLOAT_TYPE_P(other)) {
875 return f_muldiv(self,
876 adat->num, adat->den,
877 bdat->num, bdat->den,
'*');
907 return f_muldiv(self,
912 else if (RB_FLOAT_TYPE_P(other)) {
913 VALUE v = nurat_to_f(self);
923 return f_rational_new_no_reduce2(
CLASS_OF(self),
924 bdat->den, bdat->num);
926 return f_muldiv(self,
927 adat->num, adat->den,
928 bdat->num, bdat->den,
'/');
953 return nurat_to_f(self);
956 return nurat_to_f(
div);
957 if (RB_FLOAT_TYPE_P(
div))
981 if (k_rational_p(other)) {
984 if (f_one_p(dat->den))
989 if (k_numeric_p(other) &&
k_exact_p(other)) {
991 if (f_one_p(dat->den)) {
992 if (f_one_p(dat->num)) {
1016 if (INT_POSITIVE_P(other)) {
1020 else if (INT_NEGATIVE_P(other)) {
1028 if (RB_FLOAT_TYPE_P(
num)) {
1029 if (RB_FLOAT_TYPE_P(den))
1033 if (RB_FLOAT_TYPE_P(den)) {
1040 else if (RB_TYPE_P(other,
T_BIGNUM)) {
1041 rb_warn(
"in a**b, b may be too big");
1044 else if (RB_FLOAT_TYPE_P(other) || RB_TYPE_P(other,
T_RATIONAL)) {
1051#define nurat_expt rb_rational_pow
1073 switch (
TYPE(other)) {
1081 other = f_rational_new_bang1(
CLASS_OF(self), other);
1140 const double d = nurat_to_double(self);
1144 else if (RB_FLOAT_TYPE_P(other)) {
1145 const double d = nurat_to_double(self);
1171 else if (RB_FLOAT_TYPE_P(other)) {
1181 if (RB_FLOAT_TYPE_P(other)) {
1182 other = float_to_r(other);
1183 RBASIC_SET_CLASS(other,
CLASS_OF(self));
1186 other = f_rational_new_bang1(
CLASS_OF(self), other);
1203nurat_positive_p(
VALUE self)
1216nurat_negative_p(
VALUE self)
1239 if (INT_NEGATIVE_P(dat->num)) {
1241 return nurat_s_canonicalize_internal_no_reduce(
CLASS_OF(self),
num, dat->den);
1247nurat_floor(
VALUE self)
1254nurat_ceil(
VALUE self)
1275nurat_truncate(
VALUE self)
1278 if (INT_NEGATIVE_P(dat->num))
1284nurat_round_half_up(
VALUE self)
1292 neg = INT_NEGATIVE_P(
num);
1308nurat_round_half_down(
VALUE self)
1316 neg = INT_NEGATIVE_P(
num);
1333nurat_round_half_even(
VALUE self)
1341 neg = INT_NEGATIVE_P(
num);
1365 return (*func)(self);
1369 if (!k_integer_p(n))
1376 if (INT_NEGATIVE_P(n))
1381 if (!k_rational_p(s)) {
1382 s = f_rational_new_bang1(
CLASS_OF(self), s);
1390 s = nurat_truncate(s);
1399 return nurat_floor(self);
1403 return f_round_common(1, &n, self, nurat_floor);
1434 return f_round_common(
argc,
argv, self, nurat_floor);
1464 return f_round_common(
argc,
argv, self, nurat_ceil);
1494 return f_round_common(
argc,
argv, self, nurat_truncate);
1542 return f_round_common(
argc,
argv, self, round_func);
1546nurat_to_double(
VALUE self)
1567nurat_to_f(
VALUE self)
1569 return DBL2NUM(nurat_to_double(self));
1582nurat_to_r(
VALUE self)
1587#define id_ceil rb_intern("ceil")
1593 if (RB_FLOAT_TYPE_P(x))
1605 if (RB_FLOAT_TYPE_P(x))
1611#define f_reciprocal(x) f_quo(ONE, (x))
1675 VALUE c, k,
t, p0, p1, p2, q0, q1, q2;
1718 VALUE e, a, b, p, q;
1727 if (INT_NEGATIVE_P(dat->num)) {
1737 nurat_rationalize_internal(a, b, &p, &q);
1740 RATIONAL_SET_DEN(rat, q);
1743 return f_rational_new2(
CLASS_OF(self), p, q);
1763nurat_hash(
VALUE self)
1775 s = (*func)(dat->num);
1793nurat_to_s(
VALUE self)
1795 return f_format(self,
f_to_s);
1809nurat_inspect(
VALUE self)
1822nurat_dumper(
VALUE self)
1836 nurat_int_check(
num);
1837 nurat_int_check(den);
1838 nurat_canonicalize(&
num, &den);
1840 RATIONAL_SET_DEN((
VALUE)dat, den);
1848nurat_marshal_dump(
VALUE self)
1872 nurat_int_check(
num);
1873 nurat_int_check(den);
1874 nurat_canonicalize(&
num, &den);
1887 return nurat_convert(
CLASS_OF(x), dat->den, dat->num,
FALSE);
1905 other = nurat_int_value(other);
1906 return f_gcd(self, other);
1924 other = nurat_int_value(other);
1925 return f_lcm(self, other);
1943 other = nurat_int_value(other);
1944 return rb_assoc_new(f_gcd(self, other), f_lcm(self, other));
1954 if (INT_NEGATIVE_P(y)) {
1964 return nurat_s_canonicalize_internal(
rb_cRational, x, y);
1979 return nurat_numerator(rat);
1985 return nurat_denominator(rat);
1988#define id_numerator rb_intern("numerator")
1989#define f_numerator(x) rb_funcall((x), id_numerator, 0)
1991#define id_denominator rb_intern("denominator")
1992#define f_denominator(x) rb_funcall((x), id_denominator, 0)
1994#define id_to_r idTo_r
1995#define f_to_r(x) rb_funcall((x), id_to_r, 0)
2004numeric_numerator(
VALUE self)
2016numeric_denominator(
VALUE self)
2037 if (RB_FLOAT_TYPE_P(y)) {
2050 if (f_one_p(dat->den))
return dat->num;
2062integer_numerator(
VALUE self)
2074integer_denominator(
VALUE self)
2098 r = float_to_r(self);
2099 return nurat_numerator(r);
2118 r = float_to_r(self);
2119 return nurat_denominator(r);
2129nilclass_to_r(
VALUE self)
2145 return nilclass_to_r(self);
2158integer_to_r(
VALUE self)
2174 return integer_to_r(self);
2178float_decode_internal(
VALUE self,
VALUE *rf,
int *n)
2209float_to_r(
VALUE self)
2214 float_decode_internal(self, &
f, &n);
2233 VALUE e, a, b, p, q;
2240 return float_to_r(flt);
2242 nurat_rationalize_internal(a, b, &p, &q);
2249 VALUE a, b,
f, p, q, den;
2252 float_decode_internal(flt, &
f, &n);
2257 VALUE radix_times_f;
2260#if FLT_RADIX == 2 && 0
2271 return float_to_r(flt);
2275 nurat_rationalize_internal(a, b, &p, &q);
2314 return (c ==
'-' || c ==
'+');
2318read_sign(
const char **s,
const char *
const e)
2322 if (*s < e &&
issign(**s)) {
2332 return (c ==
'e' || c ==
'E');
2348read_num(
const char **s,
const char *
const end,
VALUE *
num,
VALUE *nexp)
2351 int expsign = 0, ok = 0;
2356 if (*s < end && **s !=
'.') {
2366 if (*s < end && **s ==
'.') {
2384 if (ok && *s + 1 < end && islettere(**s)) {
2386 expsign = read_sign(s, end);
2393 if (expsign ==
'-') {
2398 exp = negate_num(exp);
2407inline static const char *
2408skip_ws(
const char *s,
const char *e)
2410 while (s < e && isspace((
unsigned char)*s))
2416parse_rat(
const char *s,
const char *
const e,
int strict,
int raise)
2422 sign = read_sign(&s, e);
2424 if (!read_num(&s, e, &
num, &nexp)) {
2425 if (strict)
return Qnil;
2429 if (s < e && *s ==
'/') {
2431 if (!read_num(&s, e, &den, &dexp)) {
2432 if (strict)
return Qnil;
2435 else if (den ==
ZERO) {
2436 if (!raise)
return Qnil;
2439 else if (strict && skip_ws(s, e) != e) {
2444 nurat_reduce(&
num, &den);
2447 else if (strict && skip_ws(s, e) != e) {
2452 if (INT_NEGATIVE_P(nexp)) {
2456 if (! RB_FLOAT_TYPE_P(
mul)) {
2467 if (! RB_FLOAT_TYPE_P(
div)) {
2475 nurat_reduce(&
num, &den);
2486string_to_r_strict(
VALUE self,
int raise)
2494 if (!raise)
return Qnil;
2499 if (RB_FLOAT_TYPE_P(
num) && !FLOAT_ZERO_P(
num)) {
2500 if (!raise)
return Qnil;
2535string_to_r(
VALUE self)
2543 if (RB_FLOAT_TYPE_P(
num) && !FLOAT_ZERO_P(
num))
2555 if (RB_FLOAT_TYPE_P(
num) && !FLOAT_ZERO_P(
num))
2561to_rational(
VALUE val)
2569 VALUE a1 = numv, a2 = denv;
2575 if (!raise)
return Qnil;
2592 else if (RB_FLOAT_TYPE_P(a1)) {
2593 a1 = float_to_r(a1);
2598 else if (RB_TYPE_P(a1,
T_STRING)) {
2599 a1 = string_to_r_strict(a1, raise);
2613 else if (RB_FLOAT_TYPE_P(a2)) {
2614 a2 = float_to_r(a2);
2619 else if (RB_TYPE_P(a2,
T_STRING)) {
2620 a2 = string_to_r_strict(a2, raise);
2643 return to_rational(a1);
2647 if (!k_numeric_p(a1)) {
2659 if (!k_numeric_p(a2)) {
2671 if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
2672 (!f_integer_p(a1) || !f_integer_p(a2))) {
2680 return f_div(a1, a2);
2684 a1 = nurat_int_value(a1);
2689 else if (!k_integer_p(a2) && !raise) {
2693 a2 = nurat_int_value(a2);
2697 return nurat_s_canonicalize_internal(klass, a1, a2);
2709 return nurat_convert(klass, a1, a2,
TRUE);
2758 id_abs = rb_intern_const(
"abs");
2759 id_integer_p = rb_intern_const(
"integer?");
2760 id_i_num = rb_intern_const(
"@numerator");
2761 id_i_den = rb_intern_const(
"@denominator");
VALUE rb_assoc_new(VALUE car, VALUE cdr)
VALUE rb_big_new(size_t len, int sign)
VALUE rb_int2big(intptr_t n)
VALUE rb_str_to_inum(VALUE str, int base, int badcheck)
VALUE rb_dbl2big(double d)
VALUE rb_big_mul(VALUE x, VALUE y)
VALUE rb_big_norm(VALUE x)
VALUE rb_int_parse_cstr(const char *str, ssize_t len, char **endp, size_t *ndigits, int base, int flags)
#define MUL_OVERFLOW_LONG_P(a, b)
VALUE rb_Complex(VALUE x, VALUE y)
VALUE rb_complex_div(VALUE self, VALUE other)
Our own, locale independent, character handling routines.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
VALUE rb_int_positive_pow(long x, unsigned long y)
#define RSTRING_PTR(string)
VALUE rb_eFloatDomainError
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
void rb_undef_method(VALUE klass, const char *name)
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
void rb_raise(VALUE exc, const char *fmt,...)
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
VALUE rb_protect(VALUE(*proc)(VALUE), VALUE data, int *pstate)
Protects a function call from potential global escapes from the function.
void rb_warn(const char *fmt,...)
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Converts an object into another type.
VALUE rb_check_to_int(VALUE)
Tries to convert val into Integer.
VALUE rb_cObject
Object class.
int rb_opts_exception_p(VALUE opts, int default_value)
VALUE rb_cNilClass
NilClass class.
VALUE rb_check_convert_type_with_id(VALUE, int, const char *, ID)
VALUE rb_convert_type_with_id(VALUE v, int t, const char *nam, ID mid)
VALUE rb_equal(VALUE, VALUE)
This function is an optimized version of calling #==.
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
VALUE rb_to_int(VALUE)
Converts val into Integer.
unsigned gcd(unsigned a, unsigned b)
Thin wrapper to ruby/config.h.
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
void rb_provide(const char *)
void rb_num_zerodiv(void)
VALUE rb_dbl_cmp(double, double)
VALUE rb_num_coerce_bin(VALUE, VALUE, ID)
VALUE rb_num_coerce_cmp(VALUE, VALUE, ID)
#define rb_rational_new2(x, y)
#define rb_rational_new1(x)
void rb_must_asciicompat(VALUE)
VALUE rb_str_concat(VALUE, VALUE)
st_index_t rb_memhash(const void *ptr, long len)
#define rb_usascii_str_new2
void rb_copy_generic_ivar(VALUE, VALUE)
VALUE rb_ivar_get(VALUE, ID)
VALUE rb_ivar_set(VALUE, ID, VALUE)
int rb_respond_to(VALUE, ID)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
ID rb_intern(const char *)
Internal header for Array.
@ RB_INT_PARSE_UNDERSCORE
Internal header for Complex.
Internal header for Numeric.
int rb_int_negative_p(VALUE num)
VALUE rb_int_modulo(VALUE x, VALUE y)
VALUE rb_int_abs(VALUE num)
VALUE rb_int_div(VALUE x, VALUE y)
VALUE rb_float_pow(VALUE x, VALUE y)
VALUE rb_int_pow(VALUE x, VALUE y)
VALUE rb_int_uminus(VALUE num)
#define ROUND_FUNC(mode, name)
VALUE rb_int_equal(VALUE x, VALUE y)
VALUE rb_flo_div_flo(VALUE x, VALUE y)
VALUE rb_int_cmp(VALUE x, VALUE y)
VALUE rb_int_and(VALUE x, VALUE y)
VALUE rb_int_lshift(VALUE x, VALUE y)
int rb_num_negative_p(VALUE)
VALUE rb_float_ceil(VALUE num, int ndigits)
double rb_int_fdiv_double(VALUE x, VALUE y)
enum ruby_num_rounding_mode rb_num_get_rounding_option(VALUE opts)
VALUE rb_int_minus(VALUE x, VALUE y)
VALUE rb_int_odd_p(VALUE num)
VALUE rb_int_divmod(VALUE x, VALUE y)
VALUE rb_int_idiv(VALUE x, VALUE y)
VALUE rb_int_plus(VALUE x, VALUE y)
VALUE rb_int_mul(VALUE x, VALUE y)
Internal header for Object.
Internal header for Rational.
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
void rb_marshal_define_compat(VALUE newclass, VALUE oldclass, VALUE(*dumper)(VALUE), VALUE(*loader)(VALUE, VALUE))
Internal header for Math.
#define RARRAY_AREF(a, i)
#define k_exact_zero_p(x)
VALUE rb_rational_cmp(VALUE self, VALUE other)
VALUE rb_rational_uminus(VALUE self)
VALUE rb_gcd(VALUE self, VALUE other)
VALUE rb_rational_pow(VALUE self, VALUE other)
VALUE rb_lcm(VALUE self, VALUE other)
VALUE rb_Rational(VALUE x, VALUE y)
VALUE rb_rational_plus(VALUE self, VALUE other)
VALUE rb_cstr_to_rat(const char *s, int strict)
VALUE rb_float_denominator(VALUE self)
VALUE rb_gcd_normal(VALUE x, VALUE y)
VALUE rb_rational_new(VALUE x, VALUE y)
VALUE rb_float_numerator(VALUE self)
VALUE rb_rational_num(VALUE rat)
VALUE rb_rational_floor(VALUE self, int ndigits)
VALUE rb_rational_reciprocal(VALUE x)
VALUE rb_rational_abs(VALUE self)
VALUE rb_rational_div(VALUE self, VALUE other)
VALUE rb_flt_rationalize(VALUE flt)
VALUE rb_rational_raw(VALUE x, VALUE y)
VALUE rb_rational_minus(VALUE self, VALUE other)
st_index_t rb_rational_hash(VALUE self)
VALUE rb_flt_rationalize_with_prec(VALUE flt, VALUE prec)
VALUE rb_rational_canonicalize(VALUE x)
VALUE rb_gcdlcm(VALUE self, VALUE other)
VALUE rb_rational_den(VALUE rat)
VALUE rb_rational_mul(VALUE self, VALUE other)
VALUE rb_numeric_quo(VALUE x, VALUE y)
#define RGENGC_WB_PROTECTED_RATIONAL
const char * rb_obj_classname(VALUE)
#define RB_INTEGER_TYPE_P(obj)
size_t strlen(const char *)