[ruby-dev:32302] Re: rational
From:
tadf@...
Date:
2007-11-16 07:23:13 UTC
List:
ruby-dev #32302
rational-1.17 で > x = Rational(1073741725,-1073741824) > y = Rational(-1073741824,1073741725) > x**y #=> RangeError: ilog2 out of range of parameter となりました。 Rational(1073741725,-1073741824) #=> -1073741725/-1073741824 そもそも、ここからおかしいようです。 それとは別に、nonzero? の振舞いが仕様と違うようです (Numeric#nonzero? のままでも大丈夫な筈なので、なくてもいいと思いますが)。また、関数の宣言と 定義の不統一などがあります。そのあたりを直してみました。余計なことも していると思いますが、確認してつかえるところがあれば、取りこんでもらえれば と思います。 > ふなばさんにデータを送っていただいたのですが、たしかに性能の割には > rational.c は複雑ですね。本気で本体に取り込むことを考えるなら、もっ > とわかりやすいコードにすべきと思いました。 まだ質がどうなのか、詳しくみてませんし、まっとうな比較じゃないかもしれませんが。 1.9 で速度が出てないのが気になりますが、まずは確実なところから始めるのも いいかなと思います。
Attachments (1)
rat.patch
(16.7 KB, text/x-diff)
--- rational.c.orig Mon Nov 12 12:03:11 2007
+++ rational.c Thu Nov 15 18:51:28 2007
@@ -1,7 +1,7 @@
/*
-- rational.c
- Copyright (C) 2003 Shin-chiro Hara <sinara@blade.nagaokaut.ac.jp>
+ Copyright (C) 2003 Shin-ichiro Hara <sinara@blade.nagaokaut.ac.jp>
*/
#include "ruby.h"
@@ -17,13 +17,17 @@
#define RT_ALGEBRA
#define RT_UPC
-/* #define RT_OPT_plus */
+#if 0
+#define RT_OPT_plus
+#endif
/* Macros */
#define RATIONAL_CLASS_NAME "Rational"
+#if 0
#define RT_COERCE rb_intern("coerce")
+#endif
#define RT_FIX_UNIT INT2FIX(1)
#define RT_FIX_ZERO INT2FIX(0)
@@ -50,7 +54,7 @@
#define RT_BOTH_FIX(x, y) (FIXNUM_P(x) && FIXNUM_P(y))
#define RT_BOTH_RAT(x, y) (rb_obj_is_kind_of(x, rb_cRational) &&\
- rb_obj_is_kind_of(y, rb_cRational))
+ rb_obj_is_kind_of(y, rb_cRational))
#define RT_GCD(x, y) rb_rat_gcd(x, y)
@@ -70,11 +74,11 @@
#define RT_S_NEW2(klass, x, y) rb_rat_new2(klass, x, y)
#define RT_NEW2(x, y) rb_rat_new2(rb_obj_class(self), x, y)
-/*
+#if 0
#define RT_RAW(x, y) rb_rat_raw(rb_cRational, x, y)
#define RT_NEW1(x) rb_rat_raw(rb_cRational, x, RT_FIX_UNIT)
#define RT_NEW2(x, y) rb_rat_new2(rb_cRational, x, y)
-*/
+#endif
#define RT_PLUS(x, y) rb_funcall(x, '+', 1, y)
#define RT_MINUS(x, y) rb_funcall(x, '-', 1, y)
@@ -94,7 +98,9 @@
#define RT_l_mul(x, y) rb_rat_mul_long(x, y)
-/* #define RT_FLOOR(x) ((long)(x) > (x) ? (long)(x) - 1 : (long)(x)) */
+#if 0
+#define RT_FLOOR(x) ((long)(x) > (x) ? (long)(x) - 1 : (long)(x))
+#endif
#define RT_get \
VALUE numerator, denominator;\
@@ -121,8 +127,9 @@
static VALUE rb_rat_flo_rationalize(int, VALUE[], VALUE);
static VALUE rb_rat_min_cont_frac(VALUE, VALUE, VALUE, VALUE);
-
-/* VALUE rb_eRationalDomainError;*/
+#if 0
+VALUE rb_eRationalDomainError;
+#endif
/* Base */
VALUE rb_cRational;
@@ -141,6 +148,7 @@
{
VALUE rat;
struct RRational *r;
+
rat = Data_Make_Struct(klass, struct RRational,
rb_rat_mark, -1, r);
r->num = num;
@@ -166,6 +174,7 @@
VALUE klass, num, den;
{
VALUE gcd;
+
if (RT_ZEROP(den)) {
rb_raise(rb_eZeroDivError, "denominator is zero");
}
@@ -190,7 +199,6 @@
num = RT_UMINUS(num);
den = RT_UMINUS(den);
}
-
return RT_S_NEW0(klass, num, den);
}
}
@@ -203,7 +211,7 @@
{
VALUE num, den;
- switch(rb_scan_args(argc, argv, "11", &num, &den)){
+ switch (rb_scan_args(argc, argv, "11", &num, &den)) {
case 1:
if (!RT_KIND_OF(num, rb_cInteger)) {
rb_raise(rb_eArgError, "invalid argument type.");
@@ -215,7 +223,7 @@
}
return RT_S_NEW2(klass, num, den);
default:
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", argc, 2);
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 2);
}
}
@@ -225,7 +233,7 @@
{
struct RRational *r;
Data_Get_Struct(self, struct RRational, r);
- return(r->num);
+ return r->num;
}
static VALUE
@@ -234,17 +242,18 @@
{
struct RRational *r;
Data_Get_Struct(self, struct RRational, r);
- return(r->den);
+ return r->den;
}
/* gcd */
-/*
+#if 0
static long
rb_rat_gcd_int(a, b)
long a, b;
{
long c;
+
if (a < 0) { a = -a; }
if (b < 0) { b = -b; }
@@ -254,13 +263,14 @@
}
return a;
}
-*/
+#endif
static long
rb_rat_gcd_int(m, n)
long m, n;
{
long b, t;
+
if (m < 0) { m = -m; }
if (n < 0) { n = -n; }
if (!m) { return n; }
@@ -301,7 +311,7 @@
while (!RT_ZEROP(y)) {
if (RT_BOTH_FIX(x, y)) {
- g =rb_rat_gcd_int(FIX2LONG(x), FIX2LONG(y));
+ g = rb_rat_gcd_int(FIX2LONG(x), FIX2LONG(y));
return INT2FIX(g);
}
else {
@@ -343,7 +353,7 @@
RT_read2(other, onum, oden);
if (RT_BOTH_FIX(snum, sden) && RT_BOTH_FIX(onum, oden)) {
- return(FIX2LONG(snum) == FIX2LONG(onum) && FIX2LONG(sden) == FIX2LONG(oden) ?
+ return (FIX2LONG(snum) == FIX2LONG(onum) && FIX2LONG(sden) == FIX2LONG(oden) ?
Qtrue : Qfalse);
}
else {
@@ -371,14 +381,14 @@
case T_RATIONAL:
RT_read2(other, onum, oden);
- return(rb_funcall(rb_funcall(snum, '*', 1, oden),
+ return rb_funcall(rb_funcall(snum, '*', 1, oden),
rb_intern("<=>"), 1,
- rb_funcall(sden, '*', 1, onum)));
+ rb_funcall(sden, '*', 1, onum));
case T_FIXNUM:
case T_BIGNUM:
case T_FLOAT:
- return(rb_funcall(snum, rb_intern("<=>"), 1,
- rb_funcall(sden, '*', 1, other)));
+ return rb_funcall(snum, rb_intern("<=>"), 1,
+ rb_funcall(sden, '*', 1, other));
default:
return rb_num_coerce_cmp(self, other);
}
@@ -438,7 +448,7 @@
RT_read2(other, onum, oden);
#ifdef RT_OPT_plus
- gcd = rb_rat_gcd(sden, oden);
+ gcd = RT_GCD(sden, oden);
sden = RT_IDIV(sden, gcd);
den = RT_MUL(sden, oden);
oden = RT_IDIV(oden, gcd);
@@ -483,7 +493,7 @@
RT_read2(other, onum, oden);
#ifdef RT_OPT_plus
- gcd = rb_rat_gcd(sden, oden);
+ gcd = RT_GCD(sden, oden);
sden = RT_IDIV(sden, gcd);
den = RT_MUL(sden, oden);
oden = RT_IDIV(oden, gcd);
@@ -495,6 +505,7 @@
case T_FIXNUM:
case T_BIGNUM:
return RT_NEW2(RT_MINUS(snum, RT_MUL(other, sden)), sden);
+
case T_FLOAT:
return RT_MINUS(rb_rat_to_f(self), other);
@@ -580,11 +591,11 @@
rb_raise(rb_eZeroDivError, "division by zero");
}
- /*
+#if 0
if (RT_ZEROP(sden)) {
rb_raise(rb_eZeroDivError, "div by 0");
}
- */
+#endif
switch (RT_TYPE(other)) {
case T_RATIONAL:
@@ -741,7 +752,7 @@
case T_FLOAT:
return rb_assoc_new(other, rb_rat_to_f(self));
default:
- rb_raise(rb_eTypeError, "Can't coerce %s to Rational",
+ rb_raise(rb_eTypeError, "can't coerce %s to Rational",
rb_obj_classname(other));
}
}
@@ -760,7 +771,10 @@
VALUE self;
{
RT_get;
- return RT_ZEROP(numerator) ? Qfalse : Qtrue;
+ if (RT_ZEROP(numerator)) {
+ return Qnil;
+ }
+ return self;
}
static VALUE
@@ -810,10 +824,14 @@
VALUE str;
RT_get;
str = rb_str_new3(rb_inspect(numerator));
-// if (!RT_EQ(denominator, RT_FIX_UNIT)) {
+#if 0
+ if (!RT_EQ(denominator, RT_FIX_UNIT)) {
+#endif
rb_str_cat2(str, "/");
rb_str_concat(str, rb_inspect(denominator));
-// }
+#if 0
+ }
+#endif
return str;
}
@@ -964,7 +982,7 @@
return RT_UMINUS(rb_rat_rationalize(argc, argv, RT_UMINUS(self)));
}
- switch(rb_scan_args(argc, argv, "01", &eps)){
+ switch (rb_scan_args(argc, argv, "01", &eps)) {
case 0:
return self;
case 1:
@@ -985,7 +1003,7 @@
break;
default:
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", argc, 1);
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 1);
}
switch (RT_TYPE(eps)) {
@@ -1011,7 +1029,6 @@
}
}
-
/* etc */
static VALUE
rb_rat_dup2(klass, self)
@@ -1025,15 +1042,7 @@
rb_rat_alloc(klass)
VALUE klass;
{
- VALUE rat;
- struct RRational *r;
-
- rat = Data_Make_Struct(klass, struct RRational,
- rb_rat_mark, -1, r);
- r->num = Qnil;
- r->den = Qnil;
-
- return rat;
+ return RT_S_RAW(klass, Qnil, Qnil);
}
static VALUE
@@ -1060,7 +1069,7 @@
VALUE self;
{
RT_get;
- if (RT_NEG(numerator)){
+ if (RT_NEG(numerator)) {
return RT_NEW0(RT_UMINUS(numerator), denominator);
}
else {
@@ -1102,7 +1111,9 @@
rb_rat_int_quo(self, other)
VALUE self, other;
{
-// return RT_DIV(RT_S_NEW1(rb_cRational, self), other);
+#if 0
+ return RT_DIV(RT_S_NEW1(rb_cRational, self), other);
+#endif
return RT_S_NEW2(rb_cRational, self, other);
}
@@ -1151,7 +1162,7 @@
VALUE a, b;
a = rb_funcall(x, rb_intern("abs"), 0);
b = rb_funcall(y, rb_intern("abs"), 0);
- return RT_MUL(RT_IDIV(a, rb_rat_gcd(a, b)), b);
+ return RT_MUL(RT_IDIV(a, RT_GCD(a, b)), b);
}
static VALUE
@@ -1161,7 +1172,7 @@
VALUE a, b, gcd;
a = rb_funcall(x, rb_intern("abs"), 0);
b = rb_funcall(y, rb_intern("abs"), 0);
- gcd = rb_rat_gcd(a, b);
+ gcd = RT_GCD(a, b);
return rb_ary_new3(2, gcd, RT_MUL(RT_IDIV(a, gcd), b));
}
#endif
@@ -1173,7 +1184,8 @@
*************************************** */
-static VALUE rb_rat_flo_str_rationalize(s, eps)
+static VALUE
+rb_rat_flo_str_rationalize(s, eps)
char *s;
VALUE eps;
{
@@ -1189,7 +1201,8 @@
return rb_rat_flo_rationalize(argc, argv, RT_Float(rb_str_new2(s)));
}
-static VALUE rb_rat_intdec_str2rat(intpart, decpart, radix)
+static VALUE
+rb_rat_intdec_str2rat(intpart, decpart, radix)
char *intpart, *decpart;
int radix;
{
@@ -1211,7 +1224,8 @@
else
eat [+-]? *([0-9]([_0-9])*)?
*/
-static int rb_rat_eat_digits(pPtr, q, sPtr, badcheck, interdigits)
+static int
+rb_rat_eat_digits(pPtr, q, sPtr, badcheck, interdigits)
char **pPtr;
char *q;
int *sPtr;
@@ -1219,6 +1233,7 @@
{
long numsize = 0;
char *p = *pPtr;
+
while (!interdigits && ISSPACE(*p)) {
p++;
}
@@ -1241,7 +1256,7 @@
*q = '\0';
return 0;
}
- while(ISDIGIT(*p) || *p == '_') {
+ while (ISDIGIT(*p) || *p == '_') {
if (*p != '_') {
numsize += 1;
*q = *p;
@@ -1258,8 +1273,8 @@
return numsize;
}
-
-static VALUE rb_rat_eval_str(str, badcheck, ratz_sw, eps)
+static VALUE
+rb_rat_eval_str(str, badcheck, ratz_sw, eps)
VALUE str, eps;
int badcheck;
int ratz_sw; /* true for rationalize, false for to_r */
@@ -1269,6 +1284,7 @@
int radix = 10, sign = 0, signE = 0, noleader = 0;
long result;
char *p, *q, *s;
+
p = s = StringValuePtr(str);
rat = RT_S_NEW1(rb_cRational, RT_FIX_ZERO);
@@ -1294,7 +1310,7 @@
/**********************
Floating Point Number Expression
**********************/
- if (*p == '.'){
+ if (*p == '.') {
p++;
cden = ALLOCA_N(char, strlen(p)+1); /* right to the point */
q = cden;
@@ -1356,7 +1372,7 @@
}
if (badcheck) {
- while(ISSPACE(*p)) { p++; }
+ while (ISSPACE(*p)) { p++; }
if (*p == '\0') {
return rat;
}
@@ -1376,7 +1392,7 @@
rb_invalid_str(s, "Rational");
}
- while(ISSPACE(*p)) { p++; }
+ while (ISSPACE(*p)) { p++; }
if (*p == '/') {
p++;
@@ -1407,19 +1423,20 @@
}
}
- while(ISSPACE(*p)) { p++; }
+ while (ISSPACE(*p)) { p++; }
if (*p == '\0' || ! badcheck) {
num = rb_cstr2inum(cnum, radix);
den = rb_cstr2inum(cden, radix);
- /* this recovery for `to_r' may be inadequate.
+ /* this recovery for `to_r' may be inadequate. */
+#if 0
if (! badcheck && RT_ZEROP(den)) {
rb_warn("denominator is zero.");
rat = RT_S_NEW1(rb_cRational, num);
return sign ? RT_UMINUS(rat) : rat;
}
- */
+#endif
rat = RT_S_NEW2(rb_cRational, num, den);
return sign ? RT_UMINUS(rat) : rat;
@@ -1431,8 +1448,7 @@
rb_fatal("Error of Implementation (rb_rat_eval_str).");
}
-
-VALUE
+static VALUE
rb_rat_str_rationalize(argc, argv, str)
int argc;
VALUE *argv;
@@ -1440,7 +1456,7 @@
{
VALUE eps, eps0;
- switch(rb_scan_args(argc, argv, "01", &eps)){
+ switch (rb_scan_args(argc, argv, "01", &eps)) {
case 0:
eps = Qnil;
break;
@@ -1457,7 +1473,7 @@
break;
default:
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", argc, 1);
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 1);
}
return rb_rat_eval_str(str, Qfalse, Qtrue, eps);
@@ -1547,7 +1563,9 @@
return RT_S_NEW1(klass, val);
case T_STRING:
return rb_rat_eval_str(val, Qtrue, Qfalse, Qnil);
-/* return rb_rat_str_to_r(val); */
+#if 0
+ return rb_rat_str_to_r(val);
+#endif
case T_NIL:
rb_raise(rb_eTypeError, "can't convert nil into Rational");
default:
@@ -1568,24 +1586,18 @@
{
VALUE val, den;
- switch(rb_scan_args(argc, argv, "11", &val, &den)){
+ switch (rb_scan_args(argc, argv, "11", &val, &den)) {
case 1:
break;
case 2:
return RT_S_NEW2(rb_cRational, val, den);
default:
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", argc, 2);
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 2);
}
return rb_rat_convert(rb_cRational, val);
}
-/*****
-
- RATIONALIZE
-
-*****/
-
/*
def rationalize(r, e = nil)
return(-rationalize(-r, e)) if r < 0
@@ -1626,7 +1638,8 @@
end
*/
-VALUE rb_rat_min_cont_frac(xn, xd, yn, yd) /* Assume 0 < xn/xd < yn/yd */
+static VALUE
+rb_rat_min_cont_frac(xn, xd, yn, yd) /* Assume 0 < xn/xd < yn/yd */
VALUE xn, xd, yn, yd;
{
VALUE a, b, c, d, a0, c0;
@@ -1647,9 +1660,9 @@
yr = RARRAY(ya)->ptr[1];
if (RT_ZEROP(xr)) {
- return rb_rat_new2(rb_cRational, RT_PLUS(RT_MUL(a, xq), b), RT_PLUS(RT_MUL(c, xq), d));
+ return RT_S_NEW2(rb_cRational, RT_PLUS(RT_MUL(a, xq), b), RT_PLUS(RT_MUL(c, xq), d));
} else if (RT_LT(xq, yq)) {
- return rb_rat_new2(rb_cRational, RT_PLUS(RT_MUL(a, RT_PLUS(xq, RT_FIX_UNIT)), b), RT_PLUS(RT_MUL(c, RT_PLUS(xq, RT_FIX_UNIT)), d));
+ return RT_S_NEW2(rb_cRational, RT_PLUS(RT_MUL(a, RT_PLUS(xq, RT_FIX_UNIT)), b), RT_PLUS(RT_MUL(c, RT_PLUS(xq, RT_FIX_UNIT)), d));
} else if (RT_GT(xq, yq)) {
rb_fatal("Error of Implementation (rationalize)");
}
@@ -1668,8 +1681,7 @@
}
}
-
-VALUE
+static VALUE
rb_rat_flo_rationalize(argc, argv, flo)
int argc;
VALUE argv[];
@@ -1687,7 +1699,7 @@
return RT_UMINUS(rb_rat_flo_rationalize(argc, argv, RT_UMINUS(flo)));
}
- switch(rb_scan_args(argc, argv, "01", &eps)){
+ switch (rb_scan_args(argc, argv, "01", &eps)) {
case 0:
f0 = frexp(RFLOAT(flo)->value, &e0);
f0 = ldexp(f0, DBL_MANT_DIG);
@@ -1728,13 +1740,13 @@
}
break;
default:
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", argc, 1);
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 1);
}
return rb_rat_min_cont_frac(xn, xd, yn, yd);
}
-/*
+#if 0
VALUE
rb_rat_Rationalize(argc, argv, obj)
int argc;
@@ -1748,7 +1760,7 @@
eps0 = RT_to_s(eps);
epss = StringValuePtr(eps0);
- switch(pnum){
+ switch (pnum) {
case 1:
eps = Qnil;
break;
@@ -1763,7 +1775,7 @@
break;
default:
- rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", argc, 2);
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", argc, 2);
}
switch (RT_TYPE(flo)) {
@@ -1785,7 +1797,7 @@
rb_raise(rb_eArgError, "unkown parameter (Rationalize)");
}
-*/
+#endif
/* interface */
void
@@ -1800,13 +1812,15 @@
rb_define_singleton_method(rb_cRational, "convert", rb_rat_convert, 1);
- /*
+#if 0
rb_eRationalDomainError = rb_define_class("RationalDomainError", rb_eRangeError);
- */
+#endif
rb_define_method(rb_cRational, "inspect", rb_rat_inspect, 0);
rb_define_method(rb_cRational, "to_s", rb_rat_to_s, 0);
- /* rb_define_method(rb_cRational, "to_str", rb_rat_to_s, 0);*/
+#if 0
+ rb_define_method(rb_cRational, "to_str", rb_rat_to_s, 0);
+#endif
rb_define_method(rb_cRational, "numerator", rb_rat_numerator, 0);
rb_define_method(rb_cRational, "denominator", rb_rat_denominator, 0);
@@ -1844,7 +1858,9 @@
rb_define_method(rb_cRational, "zero?", rb_rat_zero_p, 0);
rb_define_method(rb_cRational, "nonzero?", rb_rat_nonzero_p, 0);
- /* rb_define_method(rb_cRational, "unity?", rb_rat_unit_p, 0); */
+#if 0
+ rb_define_method(rb_cRational, "unity?", rb_rat_unit_p, 0);
+#endif
rb_define_singleton_method(rb_cRational, "new!", rb_rat_raw, 2);
@@ -1865,17 +1881,15 @@
rb_define_method(rb_cRational, "rationalize", rb_rat_rationalize, -1);
/*
-
Function
-
*/
rb_define_global_function("Rational", rb_rat_Rational, -1);
- /* rb_define_global_function("Rationalize", rb_rat_Rationalize, -1); */
+#if 0
+ rb_define_global_function("Rationalize", rb_rat_Rationalize, -1);
+#endif
/*
-
Integer
-
*/
rb_undef_method(rb_cFixnum, "quo");
rb_define_method(rb_cFixnum, "quo", rb_rat_int_quo, 1);
@@ -1906,6 +1920,8 @@
rb_define_method(rb_cFloat, "decode", rb_rat_flo_decode, 0);
rb_define_method(rb_cFloat, "rationalize", rb_rat_flo_rationalize, -1);
-/* NilClass */
+/*
+ NilClass
+*/
rb_define_method(rb_cNilClass, "to_r", rb_rat_nil_to_r, 0);
}