2 rational.c: Coded by Tadayoshi Funaba 2008
4 This implementation is based on Keiju Ishitsuka's Rational library
5 which is written in ruby.
16 #define RATIONAL_NAME "Rational"
19 #define ZERO INT2FIX(0)
20 #define ONE INT2FIX(1)
21 #define TWO INT2FIX(2)
25 static ID id_Unify
, id_abs
, id_cmp
, id_convert
, id_equal_p
,
26 id_expt
, id_floor
, id_format
, id_idiv
, id_inspect
, id_negate
, id_new
,
27 id_new_bang
, id_to_f
, id_to_i
, id_to_s
, id_truncate
;
29 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
33 f_##n(VALUE x, VALUE y)\
35 return rb_funcall(x, op, 1, y);\
42 return rb_funcall(x, id_##n, 0);\
47 f_##n(VALUE x, VALUE y)\
49 return rb_funcall(x, id_##n, 1, y);\
53 f_add(VALUE x
, VALUE y
)
60 r
= rb_funcall(x
, '+', 1, y
);
62 else if (FIXNUM_P(x
)) {
66 r
= rb_funcall(x
, '+', 1, y
);
69 r
= rb_funcall(x
, '+', 1, y
);
74 f_cmp(VALUE x
, VALUE y
)
77 if (FIXNUM_P(x
) && FIXNUM_P(y
)) {
78 long c
= FIX2LONG(x
) - FIX2LONG(y
);
86 r
= rb_funcall(x
, id_cmp
, 1, y
);
91 f_div(VALUE x
, VALUE y
)
94 if (FIXNUM_P(y
) && FIX2LONG(y
) == 1)
97 r
= rb_funcall(x
, '/', 1, y
);
102 f_gt_p(VALUE x
, VALUE y
)
105 if (FIXNUM_P(x
) && FIXNUM_P(y
))
106 r
= f_boolcast(FIX2LONG(x
) > FIX2LONG(y
));
108 r
= rb_funcall(x
, '>', 1, y
);
113 f_lt_p(VALUE x
, VALUE y
)
116 if (FIXNUM_P(x
) && FIXNUM_P(y
))
117 r
= f_boolcast(FIX2LONG(x
) < FIX2LONG(y
));
119 r
= rb_funcall(x
, '<', 1, y
);
126 f_mul(VALUE x
, VALUE y
)
130 long _iy
= FIX2LONG(y
);
132 if (TYPE(x
) == T_FLOAT
)
133 r
= rb_float_new(0.0);
140 r
= rb_funcall(x
, '*', 1, y
);
142 else if (FIXNUM_P(x
)) {
143 long _ix
= FIX2LONG(x
);
145 if (TYPE(y
) == T_FLOAT
)
146 r
= rb_float_new(0.0);
153 r
= rb_funcall(x
, '*', 1, y
);
156 r
= rb_funcall(x
, '*', 1, y
);
161 f_sub(VALUE x
, VALUE y
)
165 if (FIX2LONG(y
) == 0)
168 r
= rb_funcall(x
, '-', 1, y
);
171 r
= rb_funcall(x
, '-', 1, y
);
187 f_equal_p(VALUE x
, VALUE y
)
190 if (FIXNUM_P(x
) && FIXNUM_P(y
))
191 r
= f_boolcast(FIX2LONG(x
) == FIX2LONG(y
));
193 r
= rb_funcall(x
, id_equal_p
, 1, y
);
201 f_negative_p(VALUE x
)
205 r
= f_boolcast(FIX2LONG(x
) < 0);
207 r
= rb_funcall(x
, '<', 1, ZERO
);
216 r
= f_boolcast(FIX2LONG(x
) == 0);
218 r
= rb_funcall(x
, id_equal_p
, 1, ZERO
);
227 r
= f_boolcast(FIX2LONG(x
) == 1);
229 r
= rb_funcall(x
, id_equal_p
, 1, ONE
);
234 f_kind_of_p(VALUE x
, VALUE c
)
236 return rb_obj_is_kind_of(x
, c
);
242 return f_kind_of_p(x
, rb_cNumeric
);
248 return f_kind_of_p(x
, rb_cInteger
);
254 return f_kind_of_p(x
, rb_cFloat
);
258 k_rational_p(VALUE x
)
260 return f_kind_of_p(x
, rb_cRational
);
264 #define f_gcd f_gcd_orig
268 i_gcd(long x
, long y
)
283 while ((x
& 1) == 0 && (y
& 1) == 0) {
311 f_gcd(VALUE x
, VALUE y
)
315 if (FIXNUM_P(x
) && FIXNUM_P(y
))
316 return LONG2NUM(i_gcd(FIX2LONG(x
), FIX2LONG(y
)));
330 if (FIX2LONG(x
) == 0)
333 return LONG2NUM(i_gcd(FIX2LONG(x
), FIX2LONG(y
)));
346 f_gcd(VALUE x
, VALUE y
)
348 VALUE r
= f_gcd_orig(x
, y
);
350 assert(f_zero_p(f_mod(x
, r
)));
351 assert(f_zero_p(f_mod(y
, r
)));
358 f_lcm(VALUE x
, VALUE y
)
360 if (f_zero_p(x
) || f_zero_p(y
))
363 return f_abs(f_mul(f_div(x
, f_gcd(x
, y
)), y
));
366 #define get_dat1(x) \
367 struct RRational *dat;\
368 dat = ((struct RRational *)(x))
370 #define get_dat2(x,y) \
371 struct RRational *adat, *bdat;\
372 adat = ((struct RRational *)(x));\
373 bdat = ((struct RRational *)(y))
376 nurat_s_new_internal(VALUE klass
, VALUE num
, VALUE den
)
378 NEWOBJ(obj
, struct RRational
);
379 OBJSETUP(obj
, klass
, T_RATIONAL
);
388 nurat_s_alloc(VALUE klass
)
390 return nurat_s_new_internal(klass
, ZERO
, ONE
);
394 nurat_s_new_bang(int argc
, VALUE
*argv
, VALUE klass
)
398 switch (rb_scan_args(argc
, argv
, "11", &num
, &den
)) {
400 if (!k_integer_p(num
))
405 if (!k_integer_p(num
))
407 if (!k_integer_p(den
))
410 switch (FIX2INT(f_cmp(den
, ZERO
))) {
416 rb_raise(rb_eZeroDivError
, "devided by zero");
422 return nurat_s_new_internal(klass
, num
, den
);
426 f_rational_new_bang1(VALUE klass
, VALUE x
)
428 return nurat_s_new_internal(klass
, x
, ONE
);
432 f_rational_new_bang2(VALUE klass
, VALUE x
, VALUE y
)
434 assert(!f_negative_p(y
));
435 assert(!f_zero_p(y
));
436 return nurat_s_new_internal(klass
, x
, y
);
439 #define f_unify_p(klass) rb_const_defined(klass, id_Unify)
442 nurat_int_check(VALUE num
)
449 rb_raise(rb_eArgError
, "not an integer");
454 nurat_s_canonicalize_internal(VALUE klass
, VALUE num
, VALUE den
)
458 switch (FIX2INT(f_cmp(den
, ZERO
))) {
464 rb_raise(rb_eZeroDivError
, "devided by zero");
468 gcd
= f_gcd(num
, den
);
469 num
= f_idiv(num
, gcd
);
470 den
= f_idiv(den
, gcd
);
472 if (f_one_p(den
) && f_unify_p(klass
))
475 return nurat_s_new_internal(klass
, num
, den
);
479 nurat_s_canonicalize_internal_no_reduce(VALUE klass
, VALUE num
, VALUE den
)
481 switch (FIX2INT(f_cmp(den
, ZERO
))) {
487 rb_raise(rb_eZeroDivError
, "devided by zero");
491 if (f_equal_p(den
, ONE
) && f_unify_p(klass
))
494 return nurat_s_new_internal(klass
, num
, den
);
499 nurat_s_canonicalize(int argc
, VALUE
*argv
, VALUE klass
)
503 switch (rb_scan_args(argc
, argv
, "11", &num
, &den
)) {
509 nurat_int_check(num
);
510 nurat_int_check(den
);
512 return nurat_s_canonicalize_internal(klass
, num
, den
);
517 nurat_s_new(int argc
, VALUE
*argv
, VALUE klass
)
521 switch (rb_scan_args(argc
, argv
, "11", &num
, &den
)) {
527 nurat_int_check(num
);
528 nurat_int_check(den
);
530 return nurat_s_canonicalize_internal(klass
, num
, den
);
534 f_rational_new1(VALUE klass
, VALUE x
)
536 assert(!k_rational_p(x
));
537 return nurat_s_canonicalize_internal(klass
, x
, ONE
);
541 f_rational_new2(VALUE klass
, VALUE x
, VALUE y
)
543 assert(!k_rational_p(x
));
544 assert(!k_rational_p(y
));
545 return nurat_s_canonicalize_internal(klass
, x
, y
);
549 f_rational_new_no_reduce1(VALUE klass
, VALUE x
)
551 assert(!k_rational_p(x
));
552 return nurat_s_canonicalize_internal_no_reduce(klass
, x
, ONE
);
556 f_rational_new_no_reduce2(VALUE klass
, VALUE x
, VALUE y
)
558 assert(!k_rational_p(x
));
559 assert(!k_rational_p(y
));
560 return nurat_s_canonicalize_internal_no_reduce(klass
, x
, y
);
564 nurat_f_rational(int argc
, VALUE
*argv
, VALUE klass
)
566 return rb_funcall2(rb_cRational
, id_convert
, argc
, argv
);
570 nurat_numerator(VALUE self
)
577 nurat_denominator(VALUE self
)
584 #define f_imul f_imul_orig
588 f_imul(long a
, long b
)
593 if (a
== 0 || b
== 0)
602 if (NUM2LONG(r
) != c
|| (c
/ a
) != b
)
603 r
= rb_big_mul(rb_int2big(a
), rb_int2big(b
));
611 f_imul(long x
, long y
)
613 VALUE r
= f_imul_orig(x
, y
);
614 assert(f_equal_p(r
, f_mul(LONG2NUM(x
), LONG2NUM(y
))));
620 f_addsub(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
624 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
625 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
626 long an
= FIX2LONG(anum
);
627 long ad
= FIX2LONG(aden
);
628 long bn
= FIX2LONG(bnum
);
629 long bd
= FIX2LONG(bden
);
630 long ig
= i_gcd(ad
, bd
);
632 VALUE g
= LONG2NUM(ig
);
633 VALUE a
= f_imul(an
, bd
/ ig
);
634 VALUE b
= f_imul(bn
, ad
/ ig
);
649 VALUE g
= f_gcd(aden
, bden
);
650 VALUE a
= f_mul(anum
, f_idiv(bden
, g
));
651 VALUE b
= f_mul(bnum
, f_idiv(aden
, g
));
665 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
669 nurat_add(VALUE self
, VALUE other
)
671 switch (TYPE(other
)) {
677 return f_addsub(self
,
682 return f_add(f_to_f(self
), other
);
685 get_dat2(self
, other
);
687 return f_addsub(self
,
688 adat
->num
, adat
->den
,
689 bdat
->num
, bdat
->den
, '+');
692 return rb_num_coerce_bin(self
, other
, '+');
697 nurat_sub(VALUE self
, VALUE other
)
699 switch (TYPE(other
)) {
705 return f_addsub(self
,
710 return f_sub(f_to_f(self
), other
);
713 get_dat2(self
, other
);
715 return f_addsub(self
,
716 adat
->num
, adat
->den
,
717 bdat
->num
, bdat
->den
, '-');
720 return rb_num_coerce_bin(self
, other
, '-');
725 f_muldiv(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
732 if (f_negative_p(bnum
)) {
733 anum
= f_negate(anum
);
734 bnum
= f_negate(bnum
);
741 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
742 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
743 long an
= FIX2LONG(anum
);
744 long ad
= FIX2LONG(aden
);
745 long bn
= FIX2LONG(bnum
);
746 long bd
= FIX2LONG(bden
);
747 long g1
= i_gcd(an
, bd
);
748 long g2
= i_gcd(ad
, bn
);
750 num
= f_imul(an
/ g1
, bn
/ g2
);
751 den
= f_imul(ad
/ g2
, bd
/ g1
);
754 VALUE g1
= f_gcd(anum
, bden
);
755 VALUE g2
= f_gcd(aden
, bnum
);
757 num
= f_mul(f_idiv(anum
, g1
), f_idiv(bnum
, g2
));
758 den
= f_mul(f_idiv(aden
, g2
), f_idiv(bden
, g1
));
760 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
764 nurat_mul(VALUE self
, VALUE other
)
766 switch (TYPE(other
)) {
772 return f_muldiv(self
,
777 return f_mul(f_to_f(self
), other
);
780 get_dat2(self
, other
);
782 return f_muldiv(self
,
783 adat
->num
, adat
->den
,
784 bdat
->num
, bdat
->den
, '*');
787 return rb_num_coerce_bin(self
, other
, '*');
792 nurat_div(VALUE self
, VALUE other
)
794 switch (TYPE(other
)) {
798 rb_raise(rb_eZeroDivError
, "devided by zero");
802 return f_muldiv(self
,
807 return rb_funcall(f_to_f(self
), '/', 1, other
);
810 rb_raise(rb_eZeroDivError
, "devided by zero");
812 get_dat2(self
, other
);
814 return f_muldiv(self
,
815 adat
->num
, adat
->den
,
816 bdat
->num
, bdat
->den
, '/');
819 return rb_num_coerce_bin(self
, other
, '/');
824 nurat_fdiv(VALUE self
, VALUE other
)
826 return f_div(f_to_f(self
), other
);
830 nurat_expt(VALUE self
, VALUE other
)
833 return f_rational_new_bang1(CLASS_OF(self
), ONE
);
835 if (k_rational_p(other
)) {
838 if (f_one_p(dat
->den
))
839 other
= dat
->num
; /* good? */
842 switch (TYPE(other
)) {
850 switch (FIX2INT(f_cmp(other
, ZERO
))) {
852 num
= f_expt(dat
->num
, other
);
853 den
= f_expt(dat
->den
, other
);
856 num
= f_expt(dat
->den
, f_negate(other
));
857 den
= f_expt(dat
->num
, f_negate(other
));
864 return f_rational_new2(CLASS_OF(self
), num
, den
);
868 return f_expt(f_to_f(self
), other
);
870 return rb_num_coerce_bin(self
, other
, id_expt
);
875 nurat_cmp(VALUE self
, VALUE other
)
877 switch (TYPE(other
)) {
883 if (FIXNUM_P(dat
->den
) && FIX2LONG(dat
->den
) == 1)
884 return f_cmp(dat
->num
, other
);
886 return f_cmp(self
, f_rational_new_bang1(CLASS_OF(self
), other
));
889 return f_cmp(f_to_f(self
), other
);
894 get_dat2(self
, other
);
896 if (FIXNUM_P(adat
->num
) && FIXNUM_P(adat
->den
) &&
897 FIXNUM_P(bdat
->num
) && FIXNUM_P(bdat
->den
)) {
898 num1
= f_imul(FIX2LONG(adat
->num
), FIX2LONG(bdat
->den
));
899 num2
= f_imul(FIX2LONG(bdat
->num
), FIX2LONG(adat
->den
));
902 num1
= f_mul(adat
->num
, bdat
->den
);
903 num2
= f_mul(bdat
->num
, adat
->den
);
905 return f_cmp(f_sub(num1
, num2
), ZERO
);
908 return rb_num_coerce_bin(self
, other
, id_cmp
);
913 nurat_equal_p(VALUE self
, VALUE other
)
915 switch (TYPE(other
)) {
921 if (!FIXNUM_P(dat
->den
))
923 if (FIX2LONG(dat
->den
) != 1)
925 if (f_equal_p(dat
->num
, other
))
931 return f_equal_p(f_to_f(self
), other
);
934 get_dat2(self
, other
);
936 return f_boolcast(f_equal_p(adat
->num
, bdat
->num
) &&
937 f_equal_p(adat
->den
, bdat
->den
));
940 return f_equal_p(other
, self
);
945 nurat_coerce(VALUE self
, VALUE other
)
947 switch (TYPE(other
)) {
950 return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self
), other
), self
);
952 return rb_assoc_new(other
, f_to_f(self
));
955 rb_raise(rb_eTypeError
, "%s can't be coerced into %s",
956 rb_obj_classname(other
), rb_obj_classname(self
));
961 nurat_idiv(VALUE self
, VALUE other
)
963 return f_floor(f_div(self
, other
));
967 nurat_mod(VALUE self
, VALUE other
)
969 VALUE val
= f_floor(f_div(self
, other
));
970 return f_sub(self
, f_mul(other
, val
));
974 nurat_divmod(VALUE self
, VALUE other
)
976 VALUE val
= f_floor(f_div(self
, other
));
977 return rb_assoc_new(val
, f_sub(self
, f_mul(other
, val
)));
982 nurat_quot(VALUE self
, VALUE other
)
984 return f_truncate(f_div(self
, other
));
989 nurat_rem(VALUE self
, VALUE other
)
991 VALUE val
= f_truncate(f_div(self
, other
));
992 return f_sub(self
, f_mul(other
, val
));
997 nurat_quotrem(VALUE self
, VALUE other
)
999 VALUE val
= f_truncate(f_div(self
, other
));
1000 return rb_assoc_new(val
, f_sub(self
, f_mul(other
, val
)));
1005 nurat_abs(VALUE self
)
1007 if (!f_negative_p(self
))
1010 return f_negate(self
);
1015 nurat_true(VALUE self
)
1022 nurat_floor(VALUE self
)
1025 return f_idiv(dat
->num
, dat
->den
);
1029 nurat_ceil(VALUE self
)
1032 return f_negate(f_idiv(f_negate(dat
->num
), dat
->den
));
1036 nurat_truncate(VALUE self
)
1039 if (f_negative_p(dat
->num
))
1040 return f_negate(f_idiv(f_negate(dat
->num
), dat
->den
));
1041 return f_idiv(dat
->num
, dat
->den
);
1045 nurat_round(VALUE self
)
1049 if (f_negative_p(dat
->num
)) {
1052 num
= f_negate(dat
->num
);
1053 num
= f_add(f_mul(num
, TWO
), dat
->den
);
1054 den
= f_mul(dat
->den
, TWO
);
1055 return f_negate(f_idiv(num
, den
));
1058 VALUE num
= f_add(f_mul(dat
->num
, TWO
), dat
->den
);
1059 VALUE den
= f_mul(dat
->den
, TWO
);
1060 return f_idiv(num
, den
);
1064 #define f_size(x) rb_funcall(x, rb_intern("size"), 0)
1065 #define f_rshift(x,y) rb_funcall(x, rb_intern(">>"), 1, y)
1072 assert(!f_lt_p(x
, ONE
));
1074 q
= (NUM2LONG(f_size(x
)) - sizeof(long)) * 8 + 1;
1077 x
= f_rshift(x
, LONG2NUM(q
));
1091 nurat_to_f(VALUE self
)
1095 long nl
, dl
, ml
, ne
, de
;
1102 if (f_zero_p(dat
->num
))
1103 return rb_float_new(0.0);
1109 if (f_negative_p(num
)) {
1110 num
= f_negate(num
);
1116 ml
= (long)(log(DBL_MAX
) / log(2.0) - 1); /* should be a static */
1121 num
= f_rshift(num
, LONG2NUM(ne
));
1127 den
= f_rshift(den
, LONG2NUM(de
));
1132 if ((e
> DBL_MAX_EXP
) || (e
< DBL_MIN_EXP
)) {
1133 rb_warning("%s out of Float range", rb_obj_classname(self
));
1134 return rb_float_new(e
> 0 ? HUGE_VAL
: 0.0);
1137 f
= NUM2DBL(num
) / NUM2DBL(den
);
1142 if (isinf(f
) || isnan(f
))
1143 rb_warning("%s out of Float range", rb_obj_classname(self
));
1145 return rb_float_new(f
);
1149 nurat_to_r(VALUE self
)
1155 nurat_hash(VALUE self
)
1158 return f_xor(dat
->num
, dat
->den
);
1162 nurat_to_s(VALUE self
)
1166 if (f_one_p(dat
->den
))
1167 return f_to_s(dat
->num
);
1169 return rb_funcall(rb_mKernel
, id_format
, 3,
1170 rb_str_new2("%d/%d"), dat
->num
, dat
->den
);
1174 nurat_inspect(VALUE self
)
1177 return rb_funcall(rb_mKernel
, id_format
, 3,
1178 rb_str_new2("Rational(%d, %d)"), dat
->num
, dat
->den
);
1182 nurat_marshal_dump(VALUE self
)
1185 return rb_assoc_new(dat
->num
, dat
->den
);
1189 nurat_marshal_load(VALUE self
, VALUE a
)
1192 dat
->num
= RARRAY_PTR(a
)[0];
1193 dat
->den
= RARRAY_PTR(a
)[1];
1195 if (f_zero_p(dat
->den
))
1196 rb_raise(rb_eZeroDivError
, "devided by zero");
1204 rb_gcd(VALUE self
, VALUE other
)
1206 nurat_int_check(other
);
1207 return f_gcd(self
, other
);
1211 rb_lcm(VALUE self
, VALUE other
)
1213 nurat_int_check(other
);
1214 return f_lcm(self
, other
);
1218 rb_gcdlcm(VALUE self
, VALUE other
)
1220 nurat_int_check(other
);
1221 return rb_assoc_new(f_gcd(self
, other
), f_lcm(self
, other
));
1225 rb_rational_raw(VALUE x
, VALUE y
)
1227 return nurat_s_new_internal(rb_cRational
, x
, y
);
1231 rb_rational_new(VALUE x
, VALUE y
)
1233 return nurat_s_canonicalize_internal(rb_cRational
, x
, y
);
1236 static VALUE
nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
);
1239 rb_Rational(VALUE x
, VALUE y
)
1244 return nurat_s_convert(2, a
, rb_cRational
);
1248 nilclass_to_r(VALUE self
)
1250 return rb_rational_new1(INT2FIX(0));
1254 integer_to_r(VALUE self
)
1256 return rb_rational_new1(self
);
1260 float_decode(VALUE self
)
1265 f
= frexp(RFLOAT_VALUE(self
), &n
);
1266 f
= ldexp(f
, DBL_MANT_DIG
);
1268 return rb_assoc_new(f_to_i(rb_float_new(f
)), INT2FIX(n
));
1272 float_to_r(VALUE self
)
1274 VALUE a
= float_decode(self
);
1275 return f_mul(RARRAY_PTR(a
)[0],
1276 f_expt(INT2FIX(FLT_RADIX
), RARRAY_PTR(a
)[1]));
1279 static VALUE rat_pat
, an_e_pat
, a_dot_pat
, underscores_pat
, an_underscore
;
1281 #define DIGITS "(?:\\d(?:_\\d|\\d)*)"
1282 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
1283 #define DENOMINATOR "[-+]?" DIGITS
1284 #define PATTERN "\\A([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?"
1289 static char rat_pat_source
[] = PATTERN
;
1290 static char an_e_pat_source
[] = "[eE]";
1291 static char a_dot_pat_source
[] = "\\.";
1292 static char underscores_pat_source
[] = "_+";
1294 rat_pat
= rb_reg_new(rat_pat_source
, sizeof rat_pat_source
- 1, 0);
1295 rb_global_variable(&rat_pat
);
1297 an_e_pat
= rb_reg_new(an_e_pat_source
, sizeof an_e_pat_source
- 1, 0);
1298 rb_global_variable(&an_e_pat
);
1300 a_dot_pat
= rb_reg_new(a_dot_pat_source
, sizeof a_dot_pat_source
- 1, 0);
1301 rb_global_variable(&a_dot_pat
);
1303 underscores_pat
= rb_reg_new(underscores_pat_source
,
1304 sizeof underscores_pat_source
- 1, 0);
1305 rb_global_variable(&underscores_pat
);
1307 an_underscore
= rb_str_new2("_");
1308 rb_global_variable(&an_underscore
);
1311 #define id_strip rb_intern("strip")
1312 #define f_strip(x) rb_funcall(x, id_strip, 0)
1314 #define id_match rb_intern("match")
1315 #define f_match(x,y) rb_funcall(x, id_match, 1, y)
1317 #define id_aref rb_intern("[]")
1318 #define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
1320 #define id_post_match rb_intern("post_match")
1321 #define f_post_match(x) rb_funcall(x, id_post_match, 0)
1323 #define id_split rb_intern("split")
1324 #define f_split(x,y) rb_funcall(x, id_split, 1, y)
1329 string_to_r_internal(VALUE self
)
1335 if (RSTRING_LEN(s
) == 0)
1336 return rb_assoc_new(Qnil
, self
);
1338 m
= f_match(rat_pat
, s
);
1341 VALUE v
, ifp
, exp
, ip
, fp
;
1342 VALUE si
= f_aref(m
, INT2FIX(1));
1343 VALUE nu
= f_aref(m
, INT2FIX(2));
1344 VALUE de
= f_aref(m
, INT2FIX(3));
1345 VALUE re
= f_post_match(m
);
1350 a
= f_split(nu
, an_e_pat
);
1351 ifp
= RARRAY_PTR(a
)[0];
1352 if (RARRAY_LEN(a
) != 2)
1355 exp
= RARRAY_PTR(a
)[1];
1357 a
= f_split(ifp
, a_dot_pat
);
1358 ip
= RARRAY_PTR(a
)[0];
1359 if (RARRAY_LEN(a
) != 2)
1362 fp
= RARRAY_PTR(a
)[1];
1365 v
= rb_rational_new1(f_to_i(ip
));
1368 char *p
= StringValuePtr(fp
);
1378 l
= f_expt(INT2FIX(10), LONG2NUM(count
));
1380 v
= f_add(v
, f_to_i(fp
));
1384 v
= f_mul(v
, f_expt(INT2FIX(10), f_to_i(exp
)));
1385 if (!NIL_P(si
) && *StringValuePtr(si
) == '-')
1388 v
= f_div(v
, f_to_i(de
));
1390 return rb_assoc_new(v
, re
);
1392 return rb_assoc_new(Qnil
, self
);
1396 string_to_r_strict(VALUE self
)
1398 VALUE a
= string_to_r_internal(self
);
1399 if (NIL_P(RARRAY_PTR(a
)[0]) || RSTRING_LEN(RARRAY_PTR(a
)[1]) > 0) {
1400 VALUE s
= f_inspect(self
);
1401 rb_raise(rb_eArgError
, "invalid value for Rational: %s",
1404 return RARRAY_PTR(a
)[0];
1407 #define id_gsub rb_intern("gsub")
1408 #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
1411 string_to_r(VALUE self
)
1413 VALUE s
= f_gsub(self
, underscores_pat
, an_underscore
);
1414 VALUE a
= string_to_r_internal(s
);
1415 if (!NIL_P(RARRAY_PTR(a
)[0]))
1416 return RARRAY_PTR(a
)[0];
1417 return rb_rational_new1(INT2FIX(0));
1420 #define id_to_r rb_intern("to_r")
1421 #define f_to_r(x) rb_funcall(x, id_to_r, 0)
1424 nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
)
1430 rb_scan_args(argc
, argv
, "02", &a1
, &a2
);
1434 if (k_float_p(RCOMPLEX(a1
)->image
) || !f_zero_p(RCOMPLEX(a1
)->image
)) {
1435 VALUE s
= f_to_s(a1
);
1436 rb_raise(rb_eRangeError
, "can't accept %s",
1439 a1
= RCOMPLEX(a1
)->real
;
1444 if (k_float_p(RCOMPLEX(a2
)->image
) || !f_zero_p(RCOMPLEX(a2
)->image
)) {
1445 VALUE s
= f_to_s(a2
);
1446 rb_raise(rb_eRangeError
, "can't accept %s",
1449 a2
= RCOMPLEX(a2
)->real
;
1460 a1
= string_to_r_strict(a1
);
1472 a2
= string_to_r_strict(a2
);
1478 if (NIL_P(a2
) || f_zero_p(a2
))
1481 return f_div(a1
, a2
);
1486 return f_div(a1
, a2
);
1493 return nurat_s_new(argc
, argv2
, klass
);
1498 nurat_s_induced_from(VALUE klass
, VALUE n
)
1506 assert(fprintf(stderr
, "assert() is now active\n"));
1508 id_Unify
= rb_intern("Unify");
1509 id_abs
= rb_intern("abs");
1510 id_cmp
= rb_intern("<=>");
1511 id_convert
= rb_intern("convert");
1512 id_equal_p
= rb_intern("==");
1513 id_expt
= rb_intern("**");
1514 id_floor
= rb_intern("floor");
1515 id_format
= rb_intern("format");
1516 id_idiv
= rb_intern("div");
1517 id_inspect
= rb_intern("inspect");
1518 id_negate
= rb_intern("-@");
1519 id_new
= rb_intern("new");
1520 id_new_bang
= rb_intern("new!");
1521 id_to_f
= rb_intern("to_f");
1522 id_to_i
= rb_intern("to_i");
1523 id_to_s
= rb_intern("to_s");
1524 id_truncate
= rb_intern("truncate");
1526 rb_cRational
= rb_define_class(RATIONAL_NAME
, rb_cNumeric
);
1528 rb_define_alloc_func(rb_cRational
, nurat_s_alloc
);
1529 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1530 ID2SYM(rb_intern("allocate")));
1532 rb_define_singleton_method(rb_cRational
, "new!", nurat_s_new_bang
, -1);
1533 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1534 ID2SYM(rb_intern("new!")));
1536 rb_define_singleton_method(rb_cRational
, "new", nurat_s_new
, -1);
1537 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1538 ID2SYM(rb_intern("new")));
1540 rb_define_global_function(RATIONAL_NAME
, nurat_f_rational
, -1);
1542 rb_define_method(rb_cRational
, "numerator", nurat_numerator
, 0);
1543 rb_define_method(rb_cRational
, "denominator", nurat_denominator
, 0);
1545 rb_define_method(rb_cRational
, "+", nurat_add
, 1);
1546 rb_define_method(rb_cRational
, "-", nurat_sub
, 1);
1547 rb_define_method(rb_cRational
, "*", nurat_mul
, 1);
1548 rb_define_method(rb_cRational
, "/", nurat_div
, 1);
1549 rb_define_method(rb_cRational
, "quo", nurat_div
, 1);
1550 rb_define_method(rb_cRational
, "fdiv", nurat_fdiv
, 1);
1551 rb_define_method(rb_cRational
, "**", nurat_expt
, 1);
1553 rb_define_method(rb_cRational
, "<=>", nurat_cmp
, 1);
1554 rb_define_method(rb_cRational
, "==", nurat_equal_p
, 1);
1555 rb_define_method(rb_cRational
, "coerce", nurat_coerce
, 1);
1557 rb_define_method(rb_cRational
, "div", nurat_idiv
, 1);
1559 rb_define_method(rb_cRational
, "//", nurat_idiv
, 1);
1561 rb_define_method(rb_cRational
, "modulo", nurat_mod
, 1);
1562 rb_define_method(rb_cRational
, "%", nurat_mod
, 1);
1563 rb_define_method(rb_cRational
, "divmod", nurat_divmod
, 1);
1566 rb_define_method(rb_cRational
, "quot", nurat_quot
, 1);
1568 rb_define_method(rb_cRational
, "remainder", nurat_rem
, 1);
1570 rb_define_method(rb_cRational
, "quotrem", nurat_quotrem
, 1);
1573 rb_define_method(rb_cRational
, "abs", nurat_abs
, 0);
1576 rb_define_method(rb_cRational
, "rational?", nurat_true
, 0);
1577 rb_define_method(rb_cRational
, "exact?", nurat_true
, 0);
1580 rb_define_method(rb_cRational
, "floor", nurat_floor
, 0);
1581 rb_define_method(rb_cRational
, "ceil", nurat_ceil
, 0);
1582 rb_define_method(rb_cRational
, "truncate", nurat_truncate
, 0);
1583 rb_define_method(rb_cRational
, "round", nurat_round
, 0);
1585 rb_define_method(rb_cRational
, "to_i", nurat_truncate
, 0);
1586 rb_define_method(rb_cRational
, "to_f", nurat_to_f
, 0);
1587 rb_define_method(rb_cRational
, "to_r", nurat_to_r
, 0);
1589 rb_define_method(rb_cRational
, "hash", nurat_hash
, 0);
1591 rb_define_method(rb_cRational
, "to_s", nurat_to_s
, 0);
1592 rb_define_method(rb_cRational
, "inspect", nurat_inspect
, 0);
1594 rb_define_method(rb_cRational
, "marshal_dump", nurat_marshal_dump
, 0);
1595 rb_define_method(rb_cRational
, "marshal_load", nurat_marshal_load
, 1);
1599 rb_define_method(rb_cInteger
, "gcd", rb_gcd
, 1);
1600 rb_define_method(rb_cInteger
, "lcm", rb_lcm
, 1);
1601 rb_define_method(rb_cInteger
, "gcdlcm", rb_gcdlcm
, 1);
1603 rb_define_method(rb_cNilClass
, "to_r", nilclass_to_r
, 0);
1604 rb_define_method(rb_cInteger
, "to_r", integer_to_r
, 0);
1605 rb_define_method(rb_cFloat
, "to_r", float_to_r
, 0);
1609 rb_define_method(rb_cString
, "to_r", string_to_r
, 0);
1611 rb_define_singleton_method(rb_cRational
, "convert", nurat_s_convert
, -1);
1612 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1613 ID2SYM(rb_intern("convert")));
1615 rb_include_module(rb_cRational
, rb_mPrecision
);
1616 rb_define_singleton_method(rb_cRational
, "induced_from",
1617 nurat_s_induced_from
, 1);