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 if (rb_scan_args(argc
, argv
, "11", &num
, &den
) == 1) {
507 nurat_int_check(num
);
508 nurat_int_check(den
);
510 return nurat_s_canonicalize_internal(klass
, num
, den
);
515 nurat_s_new(VALUE klass
, VALUE num
, VALUE den
)
517 nurat_int_check(num
);
518 nurat_int_check(den
);
520 return nurat_s_canonicalize_internal(klass
, num
, den
);
524 nurat_s_new_m(int argc
, VALUE
*argv
, VALUE klass
)
528 if (rb_scan_args(argc
, argv
, "11", &num
, &den
) == 1) {
531 return nurat_s_new(klass
, num
, den
);
535 f_rational_new1(VALUE klass
, VALUE x
)
537 assert(!k_rational_p(x
));
538 return nurat_s_canonicalize_internal(klass
, x
, ONE
);
542 f_rational_new2(VALUE klass
, VALUE x
, VALUE y
)
544 assert(!k_rational_p(x
));
545 assert(!k_rational_p(y
));
546 return nurat_s_canonicalize_internal(klass
, x
, y
);
550 f_rational_new_no_reduce1(VALUE klass
, VALUE x
)
552 assert(!k_rational_p(x
));
553 return nurat_s_canonicalize_internal_no_reduce(klass
, x
, ONE
);
557 f_rational_new_no_reduce2(VALUE klass
, VALUE x
, VALUE y
)
559 assert(!k_rational_p(x
));
560 assert(!k_rational_p(y
));
561 return nurat_s_canonicalize_internal_no_reduce(klass
, x
, y
);
565 nurat_f_rational(int argc
, VALUE
*argv
, VALUE klass
)
567 return rb_funcall2(rb_cRational
, id_convert
, argc
, argv
);
571 nurat_numerator(VALUE self
)
578 nurat_denominator(VALUE self
)
585 #define f_imul f_imul_orig
589 f_imul(long a
, long b
)
594 if (a
== 0 || b
== 0)
603 if (NUM2LONG(r
) != c
|| (c
/ a
) != b
)
604 r
= rb_big_mul(rb_int2big(a
), rb_int2big(b
));
612 f_imul(long x
, long y
)
614 VALUE r
= f_imul_orig(x
, y
);
615 assert(f_equal_p(r
, f_mul(LONG2NUM(x
), LONG2NUM(y
))));
621 f_addsub(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
625 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
626 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
627 long an
= FIX2LONG(anum
);
628 long ad
= FIX2LONG(aden
);
629 long bn
= FIX2LONG(bnum
);
630 long bd
= FIX2LONG(bden
);
631 long ig
= i_gcd(ad
, bd
);
633 VALUE g
= LONG2NUM(ig
);
634 VALUE a
= f_imul(an
, bd
/ ig
);
635 VALUE b
= f_imul(bn
, ad
/ ig
);
650 VALUE g
= f_gcd(aden
, bden
);
651 VALUE a
= f_mul(anum
, f_idiv(bden
, g
));
652 VALUE b
= f_mul(bnum
, f_idiv(aden
, g
));
666 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
670 nurat_add(VALUE self
, VALUE other
)
672 switch (TYPE(other
)) {
678 return f_addsub(self
,
683 return f_add(f_to_f(self
), other
);
686 get_dat2(self
, other
);
688 return f_addsub(self
,
689 adat
->num
, adat
->den
,
690 bdat
->num
, bdat
->den
, '+');
693 return rb_num_coerce_bin(self
, other
, '+');
698 nurat_sub(VALUE self
, VALUE other
)
700 switch (TYPE(other
)) {
706 return f_addsub(self
,
711 return f_sub(f_to_f(self
), other
);
714 get_dat2(self
, other
);
716 return f_addsub(self
,
717 adat
->num
, adat
->den
,
718 bdat
->num
, bdat
->den
, '-');
721 return rb_num_coerce_bin(self
, other
, '-');
726 f_muldiv(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
733 if (f_negative_p(bnum
)) {
734 anum
= f_negate(anum
);
735 bnum
= f_negate(bnum
);
742 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
743 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
744 long an
= FIX2LONG(anum
);
745 long ad
= FIX2LONG(aden
);
746 long bn
= FIX2LONG(bnum
);
747 long bd
= FIX2LONG(bden
);
748 long g1
= i_gcd(an
, bd
);
749 long g2
= i_gcd(ad
, bn
);
751 num
= f_imul(an
/ g1
, bn
/ g2
);
752 den
= f_imul(ad
/ g2
, bd
/ g1
);
755 VALUE g1
= f_gcd(anum
, bden
);
756 VALUE g2
= f_gcd(aden
, bnum
);
758 num
= f_mul(f_idiv(anum
, g1
), f_idiv(bnum
, g2
));
759 den
= f_mul(f_idiv(aden
, g2
), f_idiv(bden
, g1
));
761 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
765 nurat_mul(VALUE self
, VALUE other
)
767 switch (TYPE(other
)) {
773 return f_muldiv(self
,
778 return f_mul(f_to_f(self
), other
);
781 get_dat2(self
, other
);
783 return f_muldiv(self
,
784 adat
->num
, adat
->den
,
785 bdat
->num
, bdat
->den
, '*');
788 return rb_num_coerce_bin(self
, other
, '*');
793 nurat_div(VALUE self
, VALUE other
)
795 switch (TYPE(other
)) {
799 rb_raise(rb_eZeroDivError
, "devided by zero");
803 return f_muldiv(self
,
808 return rb_funcall(f_to_f(self
), '/', 1, other
);
811 rb_raise(rb_eZeroDivError
, "devided by zero");
813 get_dat2(self
, other
);
815 return f_muldiv(self
,
816 adat
->num
, adat
->den
,
817 bdat
->num
, bdat
->den
, '/');
820 return rb_num_coerce_bin(self
, other
, '/');
825 nurat_fdiv(VALUE self
, VALUE other
)
827 return f_div(f_to_f(self
), other
);
831 nurat_expt(VALUE self
, VALUE other
)
834 return f_rational_new_bang1(CLASS_OF(self
), ONE
);
836 if (k_rational_p(other
)) {
839 if (f_one_p(dat
->den
))
840 other
= dat
->num
; /* good? */
843 switch (TYPE(other
)) {
851 switch (FIX2INT(f_cmp(other
, ZERO
))) {
853 num
= f_expt(dat
->num
, other
);
854 den
= f_expt(dat
->den
, other
);
857 num
= f_expt(dat
->den
, f_negate(other
));
858 den
= f_expt(dat
->num
, f_negate(other
));
865 return f_rational_new2(CLASS_OF(self
), num
, den
);
869 return f_expt(f_to_f(self
), other
);
871 return rb_num_coerce_bin(self
, other
, id_expt
);
876 nurat_cmp(VALUE self
, VALUE other
)
878 switch (TYPE(other
)) {
884 if (FIXNUM_P(dat
->den
) && FIX2LONG(dat
->den
) == 1)
885 return f_cmp(dat
->num
, other
);
887 return f_cmp(self
, f_rational_new_bang1(CLASS_OF(self
), other
));
890 return f_cmp(f_to_f(self
), other
);
895 get_dat2(self
, other
);
897 if (FIXNUM_P(adat
->num
) && FIXNUM_P(adat
->den
) &&
898 FIXNUM_P(bdat
->num
) && FIXNUM_P(bdat
->den
)) {
899 num1
= f_imul(FIX2LONG(adat
->num
), FIX2LONG(bdat
->den
));
900 num2
= f_imul(FIX2LONG(bdat
->num
), FIX2LONG(adat
->den
));
903 num1
= f_mul(adat
->num
, bdat
->den
);
904 num2
= f_mul(bdat
->num
, adat
->den
);
906 return f_cmp(f_sub(num1
, num2
), ZERO
);
909 return rb_num_coerce_bin(self
, other
, id_cmp
);
914 nurat_equal_p(VALUE self
, VALUE other
)
916 switch (TYPE(other
)) {
922 if (!FIXNUM_P(dat
->den
))
924 if (FIX2LONG(dat
->den
) != 1)
926 if (f_equal_p(dat
->num
, other
))
932 return f_equal_p(f_to_f(self
), other
);
935 get_dat2(self
, other
);
937 return f_boolcast(f_equal_p(adat
->num
, bdat
->num
) &&
938 f_equal_p(adat
->den
, bdat
->den
));
941 return f_equal_p(other
, self
);
946 nurat_coerce(VALUE self
, VALUE other
)
948 switch (TYPE(other
)) {
951 return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self
), other
), self
);
953 return rb_assoc_new(other
, f_to_f(self
));
956 rb_raise(rb_eTypeError
, "%s can't be coerced into %s",
957 rb_obj_classname(other
), rb_obj_classname(self
));
962 nurat_idiv(VALUE self
, VALUE other
)
964 return f_floor(f_div(self
, other
));
968 nurat_mod(VALUE self
, VALUE other
)
970 VALUE val
= f_floor(f_div(self
, other
));
971 return f_sub(self
, f_mul(other
, val
));
975 nurat_divmod(VALUE self
, VALUE other
)
977 VALUE val
= f_floor(f_div(self
, other
));
978 return rb_assoc_new(val
, f_sub(self
, f_mul(other
, val
)));
983 nurat_quot(VALUE self
, VALUE other
)
985 return f_truncate(f_div(self
, other
));
990 nurat_rem(VALUE self
, VALUE other
)
992 VALUE val
= f_truncate(f_div(self
, other
));
993 return f_sub(self
, f_mul(other
, val
));
998 nurat_quotrem(VALUE self
, VALUE other
)
1000 VALUE val
= f_truncate(f_div(self
, other
));
1001 return rb_assoc_new(val
, f_sub(self
, f_mul(other
, val
)));
1006 nurat_abs(VALUE self
)
1008 if (!f_negative_p(self
))
1011 return f_negate(self
);
1016 nurat_true(VALUE self
)
1023 nurat_floor(VALUE self
)
1026 return f_idiv(dat
->num
, dat
->den
);
1030 nurat_ceil(VALUE self
)
1033 return f_negate(f_idiv(f_negate(dat
->num
), dat
->den
));
1037 nurat_truncate(VALUE self
)
1040 if (f_negative_p(dat
->num
))
1041 return f_negate(f_idiv(f_negate(dat
->num
), dat
->den
));
1042 return f_idiv(dat
->num
, dat
->den
);
1046 nurat_round(VALUE self
)
1050 if (f_negative_p(dat
->num
)) {
1053 num
= f_negate(dat
->num
);
1054 num
= f_add(f_mul(num
, TWO
), dat
->den
);
1055 den
= f_mul(dat
->den
, TWO
);
1056 return f_negate(f_idiv(num
, den
));
1059 VALUE num
= f_add(f_mul(dat
->num
, TWO
), dat
->den
);
1060 VALUE den
= f_mul(dat
->den
, TWO
);
1061 return f_idiv(num
, den
);
1065 #define f_size(x) rb_funcall(x, rb_intern("size"), 0)
1066 #define f_rshift(x,y) rb_funcall(x, rb_intern(">>"), 1, y)
1073 assert(!f_lt_p(x
, ONE
));
1075 q
= (NUM2LONG(f_size(x
)) - sizeof(long)) * 8 + 1;
1078 x
= f_rshift(x
, LONG2NUM(q
));
1092 nurat_to_f(VALUE self
)
1096 long nl
, dl
, ml
, ne
, de
;
1103 if (f_zero_p(dat
->num
))
1104 return rb_float_new(0.0);
1110 if (f_negative_p(num
)) {
1111 num
= f_negate(num
);
1117 ml
= (long)(log(DBL_MAX
) / log(2.0) - 1); /* should be a static */
1122 num
= f_rshift(num
, LONG2NUM(ne
));
1128 den
= f_rshift(den
, LONG2NUM(de
));
1133 if ((e
> DBL_MAX_EXP
) || (e
< DBL_MIN_EXP
)) {
1134 rb_warning("%s out of Float range", rb_obj_classname(self
));
1135 return rb_float_new(e
> 0 ? HUGE_VAL
: 0.0);
1138 f
= NUM2DBL(num
) / NUM2DBL(den
);
1143 if (isinf(f
) || isnan(f
))
1144 rb_warning("%s out of Float range", rb_obj_classname(self
));
1146 return rb_float_new(f
);
1150 nurat_to_r(VALUE self
)
1156 nurat_hash(VALUE self
)
1159 return f_xor(dat
->num
, dat
->den
);
1163 nurat_to_s(VALUE self
)
1167 if (f_one_p(dat
->den
))
1168 return f_to_s(dat
->num
);
1170 return rb_funcall(rb_mKernel
, id_format
, 3,
1171 rb_str_new2("%d/%d"), dat
->num
, dat
->den
);
1175 nurat_inspect(VALUE self
)
1178 return rb_funcall(rb_mKernel
, id_format
, 3,
1179 rb_str_new2("Rational(%d, %d)"), dat
->num
, dat
->den
);
1183 nurat_marshal_dump(VALUE self
)
1186 return rb_assoc_new(dat
->num
, dat
->den
);
1190 nurat_marshal_load(VALUE self
, VALUE a
)
1193 dat
->num
= RARRAY_PTR(a
)[0];
1194 dat
->den
= RARRAY_PTR(a
)[1];
1196 if (f_zero_p(dat
->den
))
1197 rb_raise(rb_eZeroDivError
, "devided by zero");
1205 rb_gcd(VALUE self
, VALUE other
)
1207 nurat_int_check(other
);
1208 return f_gcd(self
, other
);
1212 rb_lcm(VALUE self
, VALUE other
)
1214 nurat_int_check(other
);
1215 return f_lcm(self
, other
);
1219 rb_gcdlcm(VALUE self
, VALUE other
)
1221 nurat_int_check(other
);
1222 return rb_assoc_new(f_gcd(self
, other
), f_lcm(self
, other
));
1226 rb_rational_raw(VALUE x
, VALUE y
)
1228 return nurat_s_new_internal(rb_cRational
, x
, y
);
1232 rb_rational_new(VALUE x
, VALUE y
)
1234 return nurat_s_canonicalize_internal(rb_cRational
, x
, y
);
1237 static VALUE
nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
);
1240 rb_Rational(VALUE x
, VALUE y
)
1245 return nurat_s_convert(2, a
, rb_cRational
);
1249 nilclass_to_r(VALUE self
)
1251 return rb_rational_new1(INT2FIX(0));
1255 integer_to_r(VALUE self
)
1257 return rb_rational_new1(self
);
1261 float_decode(VALUE self
)
1266 f
= frexp(RFLOAT_VALUE(self
), &n
);
1267 f
= ldexp(f
, DBL_MANT_DIG
);
1269 return rb_assoc_new(f_to_i(rb_float_new(f
)), INT2FIX(n
));
1273 float_to_r(VALUE self
)
1275 VALUE a
= float_decode(self
);
1276 return f_mul(RARRAY_PTR(a
)[0],
1277 f_expt(INT2FIX(FLT_RADIX
), RARRAY_PTR(a
)[1]));
1280 static VALUE rat_pat
, an_e_pat
, a_dot_pat
, underscores_pat
, an_underscore
;
1282 #define DIGITS "(?:\\d(?:_\\d|\\d)*)"
1283 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
1284 #define DENOMINATOR "[-+]?" DIGITS
1285 #define PATTERN "\\A([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?"
1290 static char rat_pat_source
[] = PATTERN
;
1291 static char an_e_pat_source
[] = "[eE]";
1292 static char a_dot_pat_source
[] = "\\.";
1293 static char underscores_pat_source
[] = "_+";
1295 rat_pat
= rb_reg_new(rat_pat_source
, sizeof rat_pat_source
- 1, 0);
1296 rb_global_variable(&rat_pat
);
1298 an_e_pat
= rb_reg_new(an_e_pat_source
, sizeof an_e_pat_source
- 1, 0);
1299 rb_global_variable(&an_e_pat
);
1301 a_dot_pat
= rb_reg_new(a_dot_pat_source
, sizeof a_dot_pat_source
- 1, 0);
1302 rb_global_variable(&a_dot_pat
);
1304 underscores_pat
= rb_reg_new(underscores_pat_source
,
1305 sizeof underscores_pat_source
- 1, 0);
1306 rb_global_variable(&underscores_pat
);
1308 an_underscore
= rb_str_new2("_");
1309 rb_global_variable(&an_underscore
);
1312 #define id_strip rb_intern("strip")
1313 #define f_strip(x) rb_funcall(x, id_strip, 0)
1315 #define id_match rb_intern("match")
1316 #define f_match(x,y) rb_funcall(x, id_match, 1, y)
1318 #define id_aref rb_intern("[]")
1319 #define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
1321 #define id_post_match rb_intern("post_match")
1322 #define f_post_match(x) rb_funcall(x, id_post_match, 0)
1324 #define id_split rb_intern("split")
1325 #define f_split(x,y) rb_funcall(x, id_split, 1, y)
1330 string_to_r_internal(VALUE self
)
1336 if (RSTRING_LEN(s
) == 0)
1337 return rb_assoc_new(Qnil
, self
);
1339 m
= f_match(rat_pat
, s
);
1342 VALUE v
, ifp
, exp
, ip
, fp
;
1343 VALUE si
= f_aref(m
, INT2FIX(1));
1344 VALUE nu
= f_aref(m
, INT2FIX(2));
1345 VALUE de
= f_aref(m
, INT2FIX(3));
1346 VALUE re
= f_post_match(m
);
1351 a
= f_split(nu
, an_e_pat
);
1352 ifp
= RARRAY_PTR(a
)[0];
1353 if (RARRAY_LEN(a
) != 2)
1356 exp
= RARRAY_PTR(a
)[1];
1358 a
= f_split(ifp
, a_dot_pat
);
1359 ip
= RARRAY_PTR(a
)[0];
1360 if (RARRAY_LEN(a
) != 2)
1363 fp
= RARRAY_PTR(a
)[1];
1366 v
= rb_rational_new1(f_to_i(ip
));
1369 char *p
= StringValuePtr(fp
);
1379 l
= f_expt(INT2FIX(10), LONG2NUM(count
));
1381 v
= f_add(v
, f_to_i(fp
));
1385 v
= f_mul(v
, f_expt(INT2FIX(10), f_to_i(exp
)));
1386 if (!NIL_P(si
) && *StringValuePtr(si
) == '-')
1389 v
= f_div(v
, f_to_i(de
));
1391 return rb_assoc_new(v
, re
);
1393 return rb_assoc_new(Qnil
, self
);
1397 string_to_r_strict(VALUE self
)
1399 VALUE a
= string_to_r_internal(self
);
1400 if (NIL_P(RARRAY_PTR(a
)[0]) || RSTRING_LEN(RARRAY_PTR(a
)[1]) > 0) {
1401 VALUE s
= f_inspect(self
);
1402 rb_raise(rb_eArgError
, "invalid value for Rational: %s",
1405 return RARRAY_PTR(a
)[0];
1408 #define id_gsub rb_intern("gsub")
1409 #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
1412 string_to_r(VALUE self
)
1414 VALUE s
= f_gsub(self
, underscores_pat
, an_underscore
);
1415 VALUE a
= string_to_r_internal(s
);
1416 if (!NIL_P(RARRAY_PTR(a
)[0]))
1417 return RARRAY_PTR(a
)[0];
1418 return rb_rational_new1(INT2FIX(0));
1421 #define id_to_r rb_intern("to_r")
1422 #define f_to_r(x) rb_funcall(x, id_to_r, 0)
1425 nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
)
1429 if (rb_scan_args(argc
, argv
, "02", &a1
, &a2
) == 1) {
1435 if (k_float_p(RCOMPLEX(a1
)->image
) || !f_zero_p(RCOMPLEX(a1
)->image
)) {
1436 VALUE s
= f_to_s(a1
);
1437 rb_raise(rb_eRangeError
, "can't accept %s",
1440 a1
= RCOMPLEX(a1
)->real
;
1445 if (k_float_p(RCOMPLEX(a2
)->image
) || !f_zero_p(RCOMPLEX(a2
)->image
)) {
1446 VALUE s
= f_to_s(a2
);
1447 rb_raise(rb_eRangeError
, "can't accept %s",
1450 a2
= RCOMPLEX(a2
)->real
;
1461 a1
= string_to_r_strict(a1
);
1473 a2
= string_to_r_strict(a2
);
1479 if (NIL_P(a2
) || f_zero_p(a2
))
1482 return f_div(a1
, a2
);
1487 return f_div(a1
, a2
);
1490 return nurat_s_new(klass
, a1
, a2
);
1494 nurat_s_induced_from(VALUE klass
, VALUE n
)
1502 assert(fprintf(stderr
, "assert() is now active\n"));
1504 id_Unify
= rb_intern("Unify");
1505 id_abs
= rb_intern("abs");
1506 id_cmp
= rb_intern("<=>");
1507 id_convert
= rb_intern("convert");
1508 id_equal_p
= rb_intern("==");
1509 id_expt
= rb_intern("**");
1510 id_floor
= rb_intern("floor");
1511 id_format
= rb_intern("format");
1512 id_idiv
= rb_intern("div");
1513 id_inspect
= rb_intern("inspect");
1514 id_negate
= rb_intern("-@");
1515 id_new
= rb_intern("new");
1516 id_new_bang
= rb_intern("new!");
1517 id_to_f
= rb_intern("to_f");
1518 id_to_i
= rb_intern("to_i");
1519 id_to_s
= rb_intern("to_s");
1520 id_truncate
= rb_intern("truncate");
1522 rb_cRational
= rb_define_class(RATIONAL_NAME
, rb_cNumeric
);
1524 rb_define_alloc_func(rb_cRational
, nurat_s_alloc
);
1525 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1526 ID2SYM(rb_intern("allocate")));
1528 rb_define_singleton_method(rb_cRational
, "new!", nurat_s_new_bang
, -1);
1529 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1530 ID2SYM(rb_intern("new!")));
1532 rb_define_singleton_method(rb_cRational
, "new", nurat_s_new_m
, -1);
1533 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1534 ID2SYM(rb_intern("new")));
1536 rb_define_global_function(RATIONAL_NAME
, nurat_f_rational
, -1);
1538 rb_define_method(rb_cRational
, "numerator", nurat_numerator
, 0);
1539 rb_define_method(rb_cRational
, "denominator", nurat_denominator
, 0);
1541 rb_define_method(rb_cRational
, "+", nurat_add
, 1);
1542 rb_define_method(rb_cRational
, "-", nurat_sub
, 1);
1543 rb_define_method(rb_cRational
, "*", nurat_mul
, 1);
1544 rb_define_method(rb_cRational
, "/", nurat_div
, 1);
1545 rb_define_method(rb_cRational
, "quo", nurat_div
, 1);
1546 rb_define_method(rb_cRational
, "fdiv", nurat_fdiv
, 1);
1547 rb_define_method(rb_cRational
, "**", nurat_expt
, 1);
1549 rb_define_method(rb_cRational
, "<=>", nurat_cmp
, 1);
1550 rb_define_method(rb_cRational
, "==", nurat_equal_p
, 1);
1551 rb_define_method(rb_cRational
, "coerce", nurat_coerce
, 1);
1553 rb_define_method(rb_cRational
, "div", nurat_idiv
, 1);
1555 rb_define_method(rb_cRational
, "//", nurat_idiv
, 1);
1557 rb_define_method(rb_cRational
, "modulo", nurat_mod
, 1);
1558 rb_define_method(rb_cRational
, "%", nurat_mod
, 1);
1559 rb_define_method(rb_cRational
, "divmod", nurat_divmod
, 1);
1562 rb_define_method(rb_cRational
, "quot", nurat_quot
, 1);
1564 rb_define_method(rb_cRational
, "remainder", nurat_rem
, 1);
1566 rb_define_method(rb_cRational
, "quotrem", nurat_quotrem
, 1);
1569 rb_define_method(rb_cRational
, "abs", nurat_abs
, 0);
1572 rb_define_method(rb_cRational
, "rational?", nurat_true
, 0);
1573 rb_define_method(rb_cRational
, "exact?", nurat_true
, 0);
1576 rb_define_method(rb_cRational
, "floor", nurat_floor
, 0);
1577 rb_define_method(rb_cRational
, "ceil", nurat_ceil
, 0);
1578 rb_define_method(rb_cRational
, "truncate", nurat_truncate
, 0);
1579 rb_define_method(rb_cRational
, "round", nurat_round
, 0);
1581 rb_define_method(rb_cRational
, "to_i", nurat_truncate
, 0);
1582 rb_define_method(rb_cRational
, "to_f", nurat_to_f
, 0);
1583 rb_define_method(rb_cRational
, "to_r", nurat_to_r
, 0);
1585 rb_define_method(rb_cRational
, "hash", nurat_hash
, 0);
1587 rb_define_method(rb_cRational
, "to_s", nurat_to_s
, 0);
1588 rb_define_method(rb_cRational
, "inspect", nurat_inspect
, 0);
1590 rb_define_method(rb_cRational
, "marshal_dump", nurat_marshal_dump
, 0);
1591 rb_define_method(rb_cRational
, "marshal_load", nurat_marshal_load
, 1);
1595 rb_define_method(rb_cInteger
, "gcd", rb_gcd
, 1);
1596 rb_define_method(rb_cInteger
, "lcm", rb_lcm
, 1);
1597 rb_define_method(rb_cInteger
, "gcdlcm", rb_gcdlcm
, 1);
1599 rb_define_method(rb_cNilClass
, "to_r", nilclass_to_r
, 0);
1600 rb_define_method(rb_cInteger
, "to_r", integer_to_r
, 0);
1601 rb_define_method(rb_cFloat
, "to_r", float_to_r
, 0);
1605 rb_define_method(rb_cString
, "to_r", string_to_r
, 0);
1607 rb_define_singleton_method(rb_cRational
, "convert", nurat_s_convert
, -1);
1608 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1609 ID2SYM(rb_intern("convert")));
1611 rb_include_module(rb_cRational
, rb_mPrecision
);
1612 rb_define_singleton_method(rb_cRational
, "induced_from",
1613 nurat_s_induced_from
, 1);