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.
20 #define RATIONAL_NAME "Rational"
23 #define ZERO INT2FIX(0)
24 #define ONE INT2FIX(1)
25 #define TWO INT2FIX(2)
29 static ID id_Unify
, id_abs
, id_cmp
, id_convert
, id_equal_p
,
30 id_expt
, id_floor
, id_format
, id_idiv
, id_inspect
, id_negate
, id_new
,
31 id_new_bang
, id_to_f
, id_to_i
, id_to_s
, id_truncate
;
33 #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
37 f_##n(VALUE x, VALUE y)\
39 return rb_funcall(x, op, 1, y);\
46 return rb_funcall(x, id_##n, 0);\
51 f_##n(VALUE x, VALUE y)\
53 return rb_funcall(x, id_##n, 1, y);\
57 f_add(VALUE x
, VALUE y
)
63 else if (FIXNUM_P(x
)) {
67 return rb_funcall(x
, '+', 1, y
);
71 f_cmp(VALUE x
, VALUE y
)
73 if (FIXNUM_P(x
) && FIXNUM_P(y
)) {
74 long c
= FIX2LONG(x
) - FIX2LONG(y
);
81 return rb_funcall(x
, id_cmp
, 1, y
);
85 f_div(VALUE x
, VALUE y
)
87 if (FIXNUM_P(y
) && FIX2LONG(y
) == 1)
89 return rb_funcall(x
, '/', 1, y
);
93 f_gt_p(VALUE x
, VALUE y
)
95 if (FIXNUM_P(x
) && FIXNUM_P(y
))
96 return f_boolcast(FIX2LONG(x
) > FIX2LONG(y
));
97 return rb_funcall(x
, '>', 1, y
);
101 f_lt_p(VALUE x
, VALUE y
)
103 if (FIXNUM_P(x
) && FIXNUM_P(y
))
104 return f_boolcast(FIX2LONG(x
) < FIX2LONG(y
));
105 return rb_funcall(x
, '<', 1, y
);
111 f_mul(VALUE x
, VALUE y
)
114 long _iy
= FIX2LONG(y
);
116 if (TYPE(x
) == T_FLOAT
)
117 return rb_float_new(0.0);
124 else if (FIXNUM_P(x
)) {
125 long _ix
= FIX2LONG(x
);
127 if (TYPE(y
) == T_FLOAT
)
128 return rb_float_new(0.0);
135 return rb_funcall(x
, '*', 1, y
);
139 f_sub(VALUE x
, VALUE y
)
142 if (FIX2LONG(y
) == 0)
144 return rb_funcall(x
, '-', 1, y
);
159 f_equal_p(VALUE x
, VALUE y
)
161 if (FIXNUM_P(x
) && FIXNUM_P(y
))
162 return f_boolcast(FIX2LONG(x
) == FIX2LONG(y
));
163 return rb_funcall(x
, id_equal_p
, 1, y
);
170 f_negative_p(VALUE x
)
173 return f_boolcast(FIX2LONG(x
) < 0);
174 return rb_funcall(x
, '<', 1, ZERO
);
181 return f_boolcast(FIX2LONG(x
) == 0);
182 return rb_funcall(x
, id_equal_p
, 1, ZERO
);
189 return f_boolcast(FIX2LONG(x
) == 1);
190 return rb_funcall(x
, id_equal_p
, 1, ONE
);
194 f_kind_of_p(VALUE x
, VALUE c
)
196 return rb_obj_is_kind_of(x
, c
);
202 return f_kind_of_p(x
, rb_cNumeric
);
208 return f_kind_of_p(x
, rb_cInteger
);
214 return f_kind_of_p(x
, rb_cFloat
);
218 k_rational_p(VALUE x
)
220 return f_kind_of_p(x
, rb_cRational
);
224 #define f_gcd f_gcd_orig
228 i_gcd(long x
, long y
)
243 while ((x
& 1) == 0 && (y
& 1) == 0) {
271 f_gcd(VALUE x
, VALUE y
)
275 if (FIXNUM_P(x
) && FIXNUM_P(y
))
276 return LONG2NUM(i_gcd(FIX2LONG(x
), FIX2LONG(y
)));
290 if (FIX2LONG(x
) == 0)
293 return LONG2NUM(i_gcd(FIX2LONG(x
), FIX2LONG(y
)));
306 f_gcd(VALUE x
, VALUE y
)
308 VALUE r
= f_gcd_orig(x
, y
);
310 assert(f_zero_p(f_mod(x
, r
)));
311 assert(f_zero_p(f_mod(y
, r
)));
318 f_lcm(VALUE x
, VALUE y
)
320 if (f_zero_p(x
) || f_zero_p(y
))
322 return f_abs(f_mul(f_div(x
, f_gcd(x
, y
)), y
));
325 #define get_dat1(x) \
326 struct RRational *dat;\
327 dat = ((struct RRational *)(x))
329 #define get_dat2(x,y) \
330 struct RRational *adat, *bdat;\
331 adat = ((struct RRational *)(x));\
332 bdat = ((struct RRational *)(y))
335 nurat_s_new_internal(VALUE klass
, VALUE num
, VALUE den
)
337 NEWOBJ(obj
, struct RRational
);
338 OBJSETUP(obj
, klass
, T_RATIONAL
);
347 nurat_s_alloc(VALUE klass
)
349 return nurat_s_new_internal(klass
, ZERO
, ONE
);
353 nurat_s_new_bang(int argc
, VALUE
*argv
, VALUE klass
)
357 switch (rb_scan_args(argc
, argv
, "11", &num
, &den
)) {
359 if (!k_integer_p(num
))
364 if (!k_integer_p(num
))
366 if (!k_integer_p(den
))
369 switch (FIX2INT(f_cmp(den
, ZERO
))) {
375 rb_raise(rb_eZeroDivError
, "devided by zero");
381 return nurat_s_new_internal(klass
, num
, den
);
385 f_rational_new_bang1(VALUE klass
, VALUE x
)
387 return nurat_s_new_internal(klass
, x
, ONE
);
391 f_rational_new_bang2(VALUE klass
, VALUE x
, VALUE y
)
393 assert(!f_negative_p(y
));
394 assert(!f_zero_p(y
));
395 return nurat_s_new_internal(klass
, x
, y
);
398 #define f_unify_p(klass) rb_const_defined(klass, id_Unify)
401 nurat_int_check(VALUE num
)
408 rb_raise(rb_eArgError
, "not an integer");
413 nurat_s_canonicalize_internal(VALUE klass
, VALUE num
, VALUE den
)
417 switch (FIX2INT(f_cmp(den
, ZERO
))) {
423 rb_raise(rb_eZeroDivError
, "devided by zero");
427 gcd
= f_gcd(num
, den
);
428 num
= f_idiv(num
, gcd
);
429 den
= f_idiv(den
, gcd
);
431 if (f_one_p(den
) && f_unify_p(klass
))
433 return nurat_s_new_internal(klass
, num
, den
);
437 nurat_s_canonicalize_internal_no_reduce(VALUE klass
, VALUE num
, VALUE den
)
439 switch (FIX2INT(f_cmp(den
, ZERO
))) {
445 rb_raise(rb_eZeroDivError
, "devided by zero");
449 if (f_equal_p(den
, ONE
) && f_unify_p(klass
))
451 return nurat_s_new_internal(klass
, num
, den
);
456 nurat_s_canonicalize(int argc
, VALUE
*argv
, VALUE klass
)
460 if (rb_scan_args(argc
, argv
, "11", &num
, &den
) == 1) {
464 nurat_int_check(num
);
465 nurat_int_check(den
);
467 return nurat_s_canonicalize_internal(klass
, num
, den
);
472 nurat_s_new(int argc
, VALUE
*argv
, VALUE klass
)
476 if (rb_scan_args(argc
, argv
, "11", &num
, &den
) == 1)
479 nurat_int_check(num
);
480 nurat_int_check(den
);
482 return nurat_s_canonicalize_internal(klass
, num
, den
);
486 f_rational_new1(VALUE klass
, VALUE x
)
488 assert(!k_rational_p(x
));
489 return nurat_s_canonicalize_internal(klass
, x
, ONE
);
493 f_rational_new2(VALUE klass
, VALUE x
, VALUE y
)
495 assert(!k_rational_p(x
));
496 assert(!k_rational_p(y
));
497 return nurat_s_canonicalize_internal(klass
, x
, y
);
501 f_rational_new_no_reduce1(VALUE klass
, VALUE x
)
503 assert(!k_rational_p(x
));
504 return nurat_s_canonicalize_internal_no_reduce(klass
, x
, ONE
);
508 f_rational_new_no_reduce2(VALUE klass
, VALUE x
, VALUE y
)
510 assert(!k_rational_p(x
));
511 assert(!k_rational_p(y
));
512 return nurat_s_canonicalize_internal_no_reduce(klass
, x
, y
);
516 nurat_f_rational(int argc
, VALUE
*argv
, VALUE klass
)
518 return rb_funcall2(rb_cRational
, id_convert
, argc
, argv
);
522 nurat_numerator(VALUE self
)
529 nurat_denominator(VALUE self
)
536 #define f_imul f_imul_orig
540 f_imul(long a
, long b
)
545 if (a
== 0 || b
== 0)
554 if (NUM2LONG(r
) != c
|| (c
/ a
) != b
)
555 r
= rb_big_mul(rb_int2big(a
), rb_int2big(b
));
563 f_imul(long x
, long y
)
565 VALUE r
= f_imul_orig(x
, y
);
566 assert(f_equal_p(r
, f_mul(LONG2NUM(x
), LONG2NUM(y
))));
572 f_addsub(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
576 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
577 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
578 long an
= FIX2LONG(anum
);
579 long ad
= FIX2LONG(aden
);
580 long bn
= FIX2LONG(bnum
);
581 long bd
= FIX2LONG(bden
);
582 long ig
= i_gcd(ad
, bd
);
584 VALUE g
= LONG2NUM(ig
);
585 VALUE a
= f_imul(an
, bd
/ ig
);
586 VALUE b
= f_imul(bn
, ad
/ ig
);
601 VALUE g
= f_gcd(aden
, bden
);
602 VALUE a
= f_mul(anum
, f_idiv(bden
, g
));
603 VALUE b
= f_mul(bnum
, f_idiv(aden
, g
));
617 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
621 nurat_add(VALUE self
, VALUE other
)
623 switch (TYPE(other
)) {
629 return f_addsub(self
,
634 return f_add(f_to_f(self
), other
);
637 get_dat2(self
, other
);
639 return f_addsub(self
,
640 adat
->num
, adat
->den
,
641 bdat
->num
, bdat
->den
, '+');
644 return rb_num_coerce_bin(self
, other
, '+');
649 nurat_sub(VALUE self
, VALUE other
)
651 switch (TYPE(other
)) {
657 return f_addsub(self
,
662 return f_sub(f_to_f(self
), other
);
665 get_dat2(self
, other
);
667 return f_addsub(self
,
668 adat
->num
, adat
->den
,
669 bdat
->num
, bdat
->den
, '-');
672 return rb_num_coerce_bin(self
, other
, '-');
677 f_muldiv(VALUE self
, VALUE anum
, VALUE aden
, VALUE bnum
, VALUE bden
, int k
)
684 if (f_negative_p(bnum
)) {
685 anum
= f_negate(anum
);
686 bnum
= f_negate(bnum
);
693 if (FIXNUM_P(anum
) && FIXNUM_P(aden
) &&
694 FIXNUM_P(bnum
) && FIXNUM_P(bden
)) {
695 long an
= FIX2LONG(anum
);
696 long ad
= FIX2LONG(aden
);
697 long bn
= FIX2LONG(bnum
);
698 long bd
= FIX2LONG(bden
);
699 long g1
= i_gcd(an
, bd
);
700 long g2
= i_gcd(ad
, bn
);
702 num
= f_imul(an
/ g1
, bn
/ g2
);
703 den
= f_imul(ad
/ g2
, bd
/ g1
);
706 VALUE g1
= f_gcd(anum
, bden
);
707 VALUE g2
= f_gcd(aden
, bnum
);
709 num
= f_mul(f_idiv(anum
, g1
), f_idiv(bnum
, g2
));
710 den
= f_mul(f_idiv(aden
, g2
), f_idiv(bden
, g1
));
712 return f_rational_new_no_reduce2(CLASS_OF(self
), num
, den
);
716 nurat_mul(VALUE self
, VALUE other
)
718 switch (TYPE(other
)) {
724 return f_muldiv(self
,
729 return f_mul(f_to_f(self
), other
);
732 get_dat2(self
, other
);
734 return f_muldiv(self
,
735 adat
->num
, adat
->den
,
736 bdat
->num
, bdat
->den
, '*');
739 return rb_num_coerce_bin(self
, other
, '*');
744 nurat_div(VALUE self
, VALUE other
)
746 switch (TYPE(other
)) {
750 rb_raise(rb_eZeroDivError
, "devided by zero");
754 return f_muldiv(self
,
759 return rb_funcall(f_to_f(self
), '/', 1, other
);
762 rb_raise(rb_eZeroDivError
, "devided by zero");
764 get_dat2(self
, other
);
766 return f_muldiv(self
,
767 adat
->num
, adat
->den
,
768 bdat
->num
, bdat
->den
, '/');
771 return rb_num_coerce_bin(self
, other
, '/');
776 nurat_fdiv(VALUE self
, VALUE other
)
778 return f_div(f_to_f(self
), other
);
782 nurat_expt(VALUE self
, VALUE other
)
785 return f_rational_new_bang1(CLASS_OF(self
), ONE
);
787 if (k_rational_p(other
)) {
790 if (f_one_p(dat
->den
))
791 other
= dat
->num
; /* good? */
794 switch (TYPE(other
)) {
802 switch (FIX2INT(f_cmp(other
, ZERO
))) {
804 num
= f_expt(dat
->num
, other
);
805 den
= f_expt(dat
->den
, other
);
808 num
= f_expt(dat
->den
, f_negate(other
));
809 den
= f_expt(dat
->num
, f_negate(other
));
816 return f_rational_new2(CLASS_OF(self
), num
, den
);
820 return f_expt(f_to_f(self
), other
);
822 return rb_num_coerce_bin(self
, other
, id_expt
);
827 nurat_cmp(VALUE self
, VALUE other
)
829 switch (TYPE(other
)) {
835 if (FIXNUM_P(dat
->den
) && FIX2LONG(dat
->den
) == 1)
836 return f_cmp(dat
->num
, other
);
837 return f_cmp(self
, f_rational_new_bang1(CLASS_OF(self
), other
));
840 return f_cmp(f_to_f(self
), other
);
845 get_dat2(self
, other
);
847 if (FIXNUM_P(adat
->num
) && FIXNUM_P(adat
->den
) &&
848 FIXNUM_P(bdat
->num
) && FIXNUM_P(bdat
->den
)) {
849 num1
= f_imul(FIX2LONG(adat
->num
), FIX2LONG(bdat
->den
));
850 num2
= f_imul(FIX2LONG(bdat
->num
), FIX2LONG(adat
->den
));
853 num1
= f_mul(adat
->num
, bdat
->den
);
854 num2
= f_mul(bdat
->num
, adat
->den
);
856 return f_cmp(f_sub(num1
, num2
), ZERO
);
859 return rb_num_coerce_bin(self
, other
, id_cmp
);
864 nurat_equal_p(VALUE self
, VALUE other
)
866 switch (TYPE(other
)) {
872 if (f_zero_p(dat
->num
) && f_zero_p(other
))
875 if (!FIXNUM_P(dat
->den
))
877 if (FIX2LONG(dat
->den
) != 1)
879 if (f_equal_p(dat
->num
, other
))
884 return f_equal_p(f_to_f(self
), other
);
887 get_dat2(self
, other
);
889 if (f_zero_p(adat
->num
) && f_zero_p(bdat
->num
))
892 return f_boolcast(f_equal_p(adat
->num
, bdat
->num
) &&
893 f_equal_p(adat
->den
, bdat
->den
));
896 return f_equal_p(other
, self
);
901 nurat_coerce(VALUE self
, VALUE other
)
903 switch (TYPE(other
)) {
906 return rb_assoc_new(f_rational_new_bang1(CLASS_OF(self
), other
), self
);
908 return rb_assoc_new(other
, f_to_f(self
));
911 rb_raise(rb_eTypeError
, "%s can't be coerced into %s",
912 rb_obj_classname(other
), rb_obj_classname(self
));
917 nurat_idiv(VALUE self
, VALUE other
)
919 return f_floor(f_div(self
, other
));
923 nurat_mod(VALUE self
, VALUE other
)
925 VALUE val
= f_floor(f_div(self
, other
));
926 return f_sub(self
, f_mul(other
, val
));
930 nurat_divmod(VALUE self
, VALUE other
)
932 VALUE val
= f_floor(f_div(self
, other
));
933 return rb_assoc_new(val
, f_sub(self
, f_mul(other
, val
)));
938 nurat_quot(VALUE self
, VALUE other
)
940 return f_truncate(f_div(self
, other
));
945 nurat_rem(VALUE self
, VALUE other
)
947 VALUE val
= f_truncate(f_div(self
, other
));
948 return f_sub(self
, f_mul(other
, val
));
953 nurat_quotrem(VALUE self
, VALUE other
)
955 VALUE val
= f_truncate(f_div(self
, other
));
956 return rb_assoc_new(val
, f_sub(self
, f_mul(other
, val
)));
961 nurat_abs(VALUE self
)
963 if (!f_negative_p(self
))
965 return f_negate(self
);
970 nurat_true(VALUE self
)
977 nurat_floor(VALUE self
)
980 return f_idiv(dat
->num
, dat
->den
);
984 nurat_ceil(VALUE self
)
987 return f_negate(f_idiv(f_negate(dat
->num
), dat
->den
));
991 nurat_truncate(VALUE self
)
994 if (f_negative_p(dat
->num
))
995 return f_negate(f_idiv(f_negate(dat
->num
), dat
->den
));
996 return f_idiv(dat
->num
, dat
->den
);
1000 nurat_round(VALUE self
)
1004 if (f_negative_p(dat
->num
)) {
1007 num
= f_negate(dat
->num
);
1008 num
= f_add(f_mul(num
, TWO
), dat
->den
);
1009 den
= f_mul(dat
->den
, TWO
);
1010 return f_negate(f_idiv(num
, den
));
1013 VALUE num
= f_add(f_mul(dat
->num
, TWO
), dat
->den
);
1014 VALUE den
= f_mul(dat
->den
, TWO
);
1015 return f_idiv(num
, den
);
1019 #define f_size(x) rb_funcall(x, rb_intern("size"), 0)
1020 #define f_rshift(x,y) rb_funcall(x, rb_intern(">>"), 1, y)
1027 assert(!f_lt_p(x
, ONE
));
1029 q
= (NUM2LONG(f_size(x
)) - sizeof(long)) * 8 + 1;
1032 x
= f_rshift(x
, LONG2NUM(q
));
1046 nurat_to_f(VALUE self
)
1050 long nl
, dl
, ml
, ne
, de
;
1057 if (f_zero_p(dat
->num
))
1058 return rb_float_new(0.0);
1064 if (f_negative_p(num
)) {
1065 num
= f_negate(num
);
1071 ml
= (long)(log(DBL_MAX
) / log(2.0) - 1); /* should be a static */
1076 num
= f_rshift(num
, LONG2NUM(ne
));
1082 den
= f_rshift(den
, LONG2NUM(de
));
1087 if ((e
> DBL_MAX_EXP
) || (e
< DBL_MIN_EXP
)) {
1088 rb_warning("%s out of Float range", rb_obj_classname(self
));
1089 return rb_float_new(e
> 0 ? HUGE_VAL
: 0.0);
1092 f
= NUM2DBL(num
) / NUM2DBL(den
);
1097 if (isinf(f
) || isnan(f
))
1098 rb_warning("%s out of Float range", rb_obj_classname(self
));
1100 return rb_float_new(f
);
1104 nurat_to_r(VALUE self
)
1110 nurat_hash(VALUE self
)
1113 return f_xor(dat
->num
, dat
->den
);
1117 nurat_to_s(VALUE self
)
1121 if (f_one_p(dat
->den
))
1122 return f_to_s(dat
->num
);
1123 return rb_funcall(rb_mKernel
, id_format
, 3,
1124 rb_str_new2("%d/%d"), dat
->num
, dat
->den
);
1128 nurat_inspect(VALUE self
)
1131 return rb_funcall(rb_mKernel
, id_format
, 3,
1132 rb_str_new2("Rational(%d, %d)"), dat
->num
, dat
->den
);
1136 nurat_marshal_dump(VALUE self
)
1139 return rb_assoc_new(dat
->num
, dat
->den
);
1143 nurat_marshal_load(VALUE self
, VALUE a
)
1146 dat
->num
= RARRAY_PTR(a
)[0];
1147 dat
->den
= RARRAY_PTR(a
)[1];
1149 if (f_zero_p(dat
->den
))
1150 rb_raise(rb_eZeroDivError
, "devided by zero");
1158 rb_gcd(VALUE self
, VALUE other
)
1160 nurat_int_check(other
);
1161 return f_gcd(self
, other
);
1165 rb_lcm(VALUE self
, VALUE other
)
1167 nurat_int_check(other
);
1168 return f_lcm(self
, other
);
1172 rb_gcdlcm(VALUE self
, VALUE other
)
1174 nurat_int_check(other
);
1175 return rb_assoc_new(f_gcd(self
, other
), f_lcm(self
, other
));
1179 rb_rational_raw(VALUE x
, VALUE y
)
1181 return nurat_s_new_internal(rb_cRational
, x
, y
);
1185 rb_rational_new(VALUE x
, VALUE y
)
1187 return nurat_s_canonicalize_internal(rb_cRational
, x
, y
);
1190 static VALUE
nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
);
1193 rb_Rational(VALUE x
, VALUE y
)
1198 return nurat_s_convert(2, a
, rb_cRational
);
1202 nilclass_to_r(VALUE self
)
1204 return rb_rational_new1(INT2FIX(0));
1208 integer_to_r(VALUE self
)
1210 return rb_rational_new1(self
);
1214 float_decode(VALUE self
)
1219 f
= frexp(RFLOAT_VALUE(self
), &n
);
1220 f
= ldexp(f
, DBL_MANT_DIG
);
1222 return rb_assoc_new(f_to_i(rb_float_new(f
)), INT2FIX(n
));
1226 float_to_r(VALUE self
)
1228 VALUE a
= float_decode(self
);
1229 return f_mul(RARRAY_PTR(a
)[0],
1230 f_expt(INT2FIX(FLT_RADIX
), RARRAY_PTR(a
)[1]));
1233 static VALUE rat_pat
, an_e_pat
, a_dot_pat
, underscores_pat
, an_underscore
;
1235 #define DIGITS "(?:\\d(?:_\\d|\\d)*)"
1236 #define NUMERATOR "(?:" DIGITS "?\\.)?" DIGITS "(?:[eE][-+]?" DIGITS ")?"
1237 #define DENOMINATOR "[-+]?" DIGITS
1238 #define PATTERN "\\A([-+])?(" NUMERATOR ")(?:\\/(" DENOMINATOR "))?"
1243 static const char rat_pat_source
[] = PATTERN
;
1244 static const char an_e_pat_source
[] = "[eE]";
1245 static const char a_dot_pat_source
[] = "\\.";
1246 static const char underscores_pat_source
[] = "_+";
1248 if (rat_pat
) return;
1250 rat_pat
= rb_reg_new(rat_pat_source
, sizeof rat_pat_source
- 1, 0);
1251 rb_global_variable(&rat_pat
);
1253 an_e_pat
= rb_reg_new(an_e_pat_source
, sizeof an_e_pat_source
- 1, 0);
1254 rb_global_variable(&an_e_pat
);
1256 a_dot_pat
= rb_reg_new(a_dot_pat_source
, sizeof a_dot_pat_source
- 1, 0);
1257 rb_global_variable(&a_dot_pat
);
1259 underscores_pat
= rb_reg_new(underscores_pat_source
,
1260 sizeof underscores_pat_source
- 1, 0);
1261 rb_global_variable(&underscores_pat
);
1263 an_underscore
= rb_str_new2("_");
1264 rb_global_variable(&an_underscore
);
1267 #define id_strip rb_intern("strip")
1268 #define f_strip(x) rb_funcall(x, id_strip, 0)
1270 #define id_match rb_intern("match")
1271 #define f_match(x,y) rb_funcall(x, id_match, 1, y)
1273 #define id_aref rb_intern("[]")
1274 #define f_aref(x,y) rb_funcall(x, id_aref, 1, y)
1276 #define id_post_match rb_intern("post_match")
1277 #define f_post_match(x) rb_funcall(x, id_post_match, 0)
1279 #define id_split rb_intern("split")
1280 #define f_split(x,y) rb_funcall(x, id_split, 1, y)
1285 string_to_r_internal(VALUE self
)
1291 if (RSTRING_LEN(s
) == 0)
1292 return rb_assoc_new(Qnil
, self
);
1294 m
= f_match(rat_pat
, s
);
1297 VALUE v
, ifp
, exp
, ip
, fp
;
1298 VALUE si
= f_aref(m
, INT2FIX(1));
1299 VALUE nu
= f_aref(m
, INT2FIX(2));
1300 VALUE de
= f_aref(m
, INT2FIX(3));
1301 VALUE re
= f_post_match(m
);
1306 a
= f_split(nu
, an_e_pat
);
1307 ifp
= RARRAY_PTR(a
)[0];
1308 if (RARRAY_LEN(a
) != 2)
1311 exp
= RARRAY_PTR(a
)[1];
1313 a
= f_split(ifp
, a_dot_pat
);
1314 ip
= RARRAY_PTR(a
)[0];
1315 if (RARRAY_LEN(a
) != 2)
1318 fp
= RARRAY_PTR(a
)[1];
1321 v
= rb_rational_new1(f_to_i(ip
));
1324 char *p
= StringValuePtr(fp
);
1334 l
= f_expt(INT2FIX(10), LONG2NUM(count
));
1336 v
= f_add(v
, f_to_i(fp
));
1340 v
= f_mul(v
, f_expt(INT2FIX(10), f_to_i(exp
)));
1341 if (!NIL_P(si
) && *StringValuePtr(si
) == '-')
1344 v
= f_div(v
, f_to_i(de
));
1346 return rb_assoc_new(v
, re
);
1348 return rb_assoc_new(Qnil
, self
);
1352 string_to_r_strict(VALUE self
)
1354 VALUE a
= string_to_r_internal(self
);
1355 if (NIL_P(RARRAY_PTR(a
)[0]) || RSTRING_LEN(RARRAY_PTR(a
)[1]) > 0) {
1356 VALUE s
= f_inspect(self
);
1357 rb_raise(rb_eArgError
, "invalid value for Rational: %s",
1360 return RARRAY_PTR(a
)[0];
1363 #define id_gsub rb_intern("gsub")
1364 #define f_gsub(x,y,z) rb_funcall(x, id_gsub, 2, y, z)
1367 string_to_r(VALUE self
)
1369 VALUE s
, a
, backref
;
1371 backref
= rb_backref_get();
1372 rb_match_busy(backref
);
1374 s
= f_gsub(self
, underscores_pat
, an_underscore
);
1375 a
= string_to_r_internal(s
);
1377 rb_backref_set(backref
);
1379 if (!NIL_P(RARRAY_PTR(a
)[0]))
1380 return RARRAY_PTR(a
)[0];
1381 return rb_rational_new1(INT2FIX(0));
1384 #define id_to_r rb_intern("to_r")
1385 #define f_to_r(x) rb_funcall(x, id_to_r, 0)
1388 nurat_s_convert(int argc
, VALUE
*argv
, VALUE klass
)
1390 VALUE a1
, a2
, backref
;
1392 rb_scan_args(argc
, argv
, "02", &a1
, &a2
);
1396 if (k_float_p(RCOMPLEX(a1
)->image
) || !f_zero_p(RCOMPLEX(a1
)->image
)) {
1397 VALUE s
= f_to_s(a1
);
1398 rb_raise(rb_eRangeError
, "can't accept %s",
1401 a1
= RCOMPLEX(a1
)->real
;
1406 if (k_float_p(RCOMPLEX(a2
)->image
) || !f_zero_p(RCOMPLEX(a2
)->image
)) {
1407 VALUE s
= f_to_s(a2
);
1408 rb_raise(rb_eRangeError
, "can't accept %s",
1411 a2
= RCOMPLEX(a2
)->real
;
1414 backref
= rb_backref_get();
1415 rb_match_busy(backref
);
1425 a1
= string_to_r_strict(a1
);
1437 a2
= string_to_r_strict(a2
);
1441 rb_backref_set(backref
);
1445 if (NIL_P(a2
) || f_zero_p(a2
))
1447 return f_div(a1
, a2
);
1452 return f_div(a1
, a2
);
1459 return nurat_s_new(argc
, argv2
, klass
);
1464 nurat_s_induced_from(VALUE klass
, VALUE n
)
1473 #define rb_intern(str) rb_intern_const(str)
1475 assert(fprintf(stderr
, "assert() is now active\n"));
1477 id_Unify
= rb_intern("Unify");
1478 id_abs
= rb_intern("abs");
1479 id_cmp
= rb_intern("<=>");
1480 id_convert
= rb_intern("convert");
1481 id_equal_p
= rb_intern("==");
1482 id_expt
= rb_intern("**");
1483 id_floor
= rb_intern("floor");
1484 id_format
= rb_intern("format");
1485 id_idiv
= rb_intern("div");
1486 id_inspect
= rb_intern("inspect");
1487 id_negate
= rb_intern("-@");
1488 id_new
= rb_intern("new");
1489 id_new_bang
= rb_intern("new!");
1490 id_to_f
= rb_intern("to_f");
1491 id_to_i
= rb_intern("to_i");
1492 id_to_s
= rb_intern("to_s");
1493 id_truncate
= rb_intern("truncate");
1495 rb_cRational
= rb_define_class(RATIONAL_NAME
, rb_cNumeric
);
1497 rb_define_alloc_func(rb_cRational
, nurat_s_alloc
);
1498 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1499 ID2SYM(rb_intern("allocate")));
1501 rb_define_singleton_method(rb_cRational
, "new!", nurat_s_new_bang
, -1);
1502 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1503 ID2SYM(rb_intern("new!")));
1505 rb_define_singleton_method(rb_cRational
, "new", nurat_s_new
, -1);
1506 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1507 ID2SYM(rb_intern("new")));
1509 rb_define_global_function(RATIONAL_NAME
, nurat_f_rational
, -1);
1511 rb_define_method(rb_cRational
, "numerator", nurat_numerator
, 0);
1512 rb_define_method(rb_cRational
, "denominator", nurat_denominator
, 0);
1514 rb_define_method(rb_cRational
, "+", nurat_add
, 1);
1515 rb_define_method(rb_cRational
, "-", nurat_sub
, 1);
1516 rb_define_method(rb_cRational
, "*", nurat_mul
, 1);
1517 rb_define_method(rb_cRational
, "/", nurat_div
, 1);
1518 rb_define_method(rb_cRational
, "quo", nurat_div
, 1);
1519 rb_define_method(rb_cRational
, "fdiv", nurat_fdiv
, 1);
1520 rb_define_method(rb_cRational
, "**", nurat_expt
, 1);
1522 rb_define_method(rb_cRational
, "<=>", nurat_cmp
, 1);
1523 rb_define_method(rb_cRational
, "==", nurat_equal_p
, 1);
1524 rb_define_method(rb_cRational
, "coerce", nurat_coerce
, 1);
1526 rb_define_method(rb_cRational
, "div", nurat_idiv
, 1);
1528 rb_define_method(rb_cRational
, "//", nurat_idiv
, 1);
1530 rb_define_method(rb_cRational
, "modulo", nurat_mod
, 1);
1531 rb_define_method(rb_cRational
, "%", nurat_mod
, 1);
1532 rb_define_method(rb_cRational
, "divmod", nurat_divmod
, 1);
1535 rb_define_method(rb_cRational
, "quot", nurat_quot
, 1);
1537 rb_define_method(rb_cRational
, "remainder", nurat_rem
, 1);
1539 rb_define_method(rb_cRational
, "quotrem", nurat_quotrem
, 1);
1542 rb_define_method(rb_cRational
, "abs", nurat_abs
, 0);
1545 rb_define_method(rb_cRational
, "rational?", nurat_true
, 0);
1546 rb_define_method(rb_cRational
, "exact?", nurat_true
, 0);
1549 rb_define_method(rb_cRational
, "floor", nurat_floor
, 0);
1550 rb_define_method(rb_cRational
, "ceil", nurat_ceil
, 0);
1551 rb_define_method(rb_cRational
, "truncate", nurat_truncate
, 0);
1552 rb_define_method(rb_cRational
, "round", nurat_round
, 0);
1554 rb_define_method(rb_cRational
, "to_i", nurat_truncate
, 0);
1555 rb_define_method(rb_cRational
, "to_f", nurat_to_f
, 0);
1556 rb_define_method(rb_cRational
, "to_r", nurat_to_r
, 0);
1558 rb_define_method(rb_cRational
, "hash", nurat_hash
, 0);
1560 rb_define_method(rb_cRational
, "to_s", nurat_to_s
, 0);
1561 rb_define_method(rb_cRational
, "inspect", nurat_inspect
, 0);
1563 rb_define_method(rb_cRational
, "marshal_dump", nurat_marshal_dump
, 0);
1564 rb_define_method(rb_cRational
, "marshal_load", nurat_marshal_load
, 1);
1568 rb_define_method(rb_cInteger
, "gcd", rb_gcd
, 1);
1569 rb_define_method(rb_cInteger
, "lcm", rb_lcm
, 1);
1570 rb_define_method(rb_cInteger
, "gcdlcm", rb_gcdlcm
, 1);
1572 rb_define_method(rb_cNilClass
, "to_r", nilclass_to_r
, 0);
1573 rb_define_method(rb_cInteger
, "to_r", integer_to_r
, 0);
1574 rb_define_method(rb_cFloat
, "to_r", float_to_r
, 0);
1578 rb_define_method(rb_cString
, "to_r", string_to_r
, 0);
1580 rb_define_singleton_method(rb_cRational
, "convert", nurat_s_convert
, -1);
1581 rb_funcall(rb_cRational
, rb_intern("private_class_method"), 1,
1582 ID2SYM(rb_intern("convert")));
1584 rb_include_module(rb_cRational
, rb_mPrecision
);
1585 rb_define_singleton_method(rb_cRational
, "induced_from",
1586 nurat_s_induced_from
, 1);