diff options
| author | Yukihiro Matsumoto <[email protected]> | 2012-05-02 08:51:43 +0900 |
|---|---|---|
| committer | Yukihiro Matsumoto <[email protected]> | 2012-05-02 08:51:43 +0900 |
| commit | e1f7617ff6c4baee5be4bef18c14cb7f471a0577 (patch) | |
| tree | df1454e3d5f0327dbd2c230ff77e9924641f701d /src | |
| parent | f373169af0031b1f1b10062be1f11d1d047894df (diff) | |
| download | mruby-e1f7617ff6c4baee5be4bef18c14cb7f471a0577.tar.gz mruby-e1f7617ff6c4baee5be4bef18c14cb7f471a0577.zip | |
numeric.c: big restructuring; coercing removed, indentation fixed, unnecessary code removed
Diffstat (limited to 'src')
| -rw-r--r-- | src/numeric.c | 1012 |
1 files changed, 270 insertions, 742 deletions
diff --git a/src/numeric.c b/src/numeric.c index 72cfb0c7e..f14a10993 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -28,61 +28,8 @@ #include <ieeefp.h> #endif -/* use IEEE 64bit values if not defined */ -#ifndef FLT_RADIX -#define FLT_RADIX 2 -#endif -#ifndef FLT_ROUNDS -#define FLT_ROUNDS 1 -#endif -#ifndef DBL_MIN -#define DBL_MIN 2.2250738585072014e-308 -#endif -#ifndef DBL_MAX -#define DBL_MAX 1.7976931348623157e+308 -#endif -#ifndef DBL_MIN_EXP -#define DBL_MIN_EXP (-1021) -#endif -#ifndef DBL_MAX_EXP -#define DBL_MAX_EXP 1024 -#endif -#ifndef DBL_MIN_10_EXP -#define DBL_MIN_10_EXP (-307) -#endif -#ifndef DBL_MAX_10_EXP -#define DBL_MAX_10_EXP 308 -#endif -#ifndef DBL_DIG -#define DBL_DIG 15 -#endif -#ifndef DBL_MANT_DIG -#define DBL_MANT_DIG 53 -#endif -#ifndef DBL_EPSILON -#define DBL_EPSILON 2.2204460492503131e-16 -#endif - -#define mrb_rational_raw1(x) mrb_rational_raw(x, INT2FIX(1)) - -typedef uintptr_t VALUE; -typedef uintptr_t ID; #define SIGNED_VALUE intptr_t -#ifdef HAVE_INFINITY -#elif BYTE_ORDER == LITTLE_ENDIAN -const unsigned char mrb_infinity[] = "\x00\x00\x80\x7f"; -#else -const unsigned char mrb_infinity[] = "\x7f\x80\x00\x00"; -#endif - -#ifdef HAVE_NAN -#elif BYTE_ORDER == LITTLE_ENDIAN -const unsigned char mrb_nan[] = "\x00\x00\xc0\x7f"; -#else -const unsigned char mrb_nan[] = "\x7f\xc0\x00\x00"; -#endif - #ifdef MRB_USE_FLOAT #define floor(f) floorf(f) #define ceil(f) ceilf(f) @@ -90,24 +37,6 @@ const unsigned char mrb_nan[] = "\x7f\xc0\x00\x00"; #define fmod(x,y) fmodf(x,y) #endif -static mrb_float -mrb_round(mrb_float x) -{ - mrb_float f; - - if (x > 0.0) { - f = floor(x); - x = f + (x - f >= 0.5); - } - else if (x < 0.0) { - f = ceil(x); - x = f - (f - x >= 0.5); - } - return x; -} - -#define round(x) mrb_round(x) - void mrb_cmperr(mrb_state *mrb, mrb_value x, mrb_value y); void @@ -116,103 +45,18 @@ mrb_num_zerodiv(mrb_state *mrb) mrb_raise(mrb, E_ZERODIVISION_ERROR, "divided by 0"); } - -/* - * call-seq: - * num.coerce(numeric) -> array - * - * If <i>aNumeric</i> is the same type as <i>num</i>, returns an array - * containing <i>aNumeric</i> and <i>num</i>. Otherwise, returns an - * array with both <i>aNumeric</i> and <i>num</i> represented as - * <code>Float</code> objects. This coercion mechanism is used by - * Ruby to handle mixed-type numeric operations: it is intended to - * find a compatible common type between the two operands of the operator. - * - * 1.coerce(2.5) #=> [2.5, 1.0] - * 1.2.coerce(3) #=> [3.0, 1.2] - * 1.coerce(2) #=> [2, 1] - */ - -static mrb_value -num_coerce(mrb_state *mrb, mrb_value x) -{ - mrb_value y; - mrb_get_args(mrb, "o", &y); - - //if (CLASS_OF(x) == CLASS_OF(y)) - if (mrb_class(mrb, x) == mrb_class(mrb, y)) - return mrb_assoc_new(mrb, y, x); - x = mrb_Float(mrb, x); - y = mrb_Float(mrb, y); - return mrb_assoc_new(mrb, y, x); -} - -static mrb_value -coerce_body(mrb_state *mrb, mrb_value *x) -{ - return mrb_funcall(mrb, x[1], "coerce", 1, x[0]); -} - -static mrb_value -coerce_rescue(mrb_state *mrb, mrb_value *x) -{ - volatile mrb_value v = mrb_inspect(mrb, x[1]); - - mrb_raise(mrb, E_TYPE_ERROR, "%s can't be coerced into %s", - mrb_special_const_p(x[1])? - RSTRING_PTR(v): - mrb_obj_classname(mrb, x[1]), - mrb_obj_classname(mrb, x[0])); - return mrb_nil_value(); /* dummy */ -} - -static int -do_coerce(mrb_state *mrb, mrb_value *x, mrb_value *y, int err) -{ - mrb_value ary; - mrb_value a[2]; - - a[0] = *x; a[1] = *y; - - ary = coerce_body(mrb, a); - if (mrb_type(ary) != MRB_TT_ARRAY || RARRAY_LEN(ary) != 2) { - if (err) { - mrb_raise(mrb, E_TYPE_ERROR, "coerce must return [x, y]"); - } - return FALSE; - } - - *x = RARRAY_PTR(ary)[0]; - *y = RARRAY_PTR(ary)[1]; - return TRUE; -} - -mrb_value -mrb_num_coerce_bin(mrb_state *mrb, mrb_value x, mrb_value y, char* func) -{ - do_coerce(mrb, &x, &y, TRUE); - return mrb_funcall(mrb, x, func, 1, y); -} - -mrb_value -mrb_num_coerce_cmp(mrb_state *mrb, mrb_value x, mrb_value y, char* func) -{ - if (do_coerce(mrb, &x, &y, FALSE)) - return mrb_funcall(mrb, x, func, 1, y); - return mrb_nil_value(); -} - -mrb_value -mrb_num_coerce_relop(mrb_state *mrb, mrb_value x, mrb_value y, char* func) -{ - mrb_value c, x0 = x, y0 = y; - - if (!do_coerce(mrb, &x, &y, FALSE) || - mrb_nil_p(c = mrb_funcall(mrb, x, func, 1, y))) { - mrb_cmperr(mrb, x0, y0); - return mrb_nil_value(); /* not reached */ - } - return c; +static mrb_float +mrb_to_flo(mrb_state *mrb, mrb_value val) +{ + switch (mrb_type(val)) { + case MRB_TT_FIXNUM: + return (mrb_float)mrb_fixnum(val); + case MRB_TT_FLOAT: + break; + default: + mrb_raise(mrb, E_TYPE_ERROR, "non float value"); + } + return mrb_float(val); } /* @@ -225,7 +69,7 @@ mrb_num_coerce_relop(mrb_state *mrb, mrb_value x, mrb_value y, char* func) static mrb_value num_uplus(mrb_state *mrb, mrb_value num) { - return num; + return num; } /* @@ -238,27 +82,28 @@ num_uplus(mrb_state *mrb, mrb_value num) static mrb_value num_uminus(mrb_state *mrb, mrb_value num) { - mrb_value zero; - - zero = mrb_fixnum_value(0); - do_coerce(mrb, &zero, &num, TRUE); + return mrb_float_value((mrb_float)0 - mrb_to_flo(mrb, num)); +} - return mrb_funcall(mrb, zero, "-", 1, num); +static mrb_value +fix_uminus(mrb_state *mrb, mrb_value num) +{ + return mrb_fixnum_value(0 - mrb_fixnum(num)); } /* * call-seq: * num.quo(numeric) -> real * - * Returns most exact division (rational for integers, float for floats). + * Returns most exact division. */ static mrb_value num_quo(mrb_state *mrb, mrb_value x) { - mrb_value y; + mrb_value y; - mrb_get_args(mrb, "o", &y); - return mrb_funcall(mrb, mrb_float_value((mrb_float)mrb_fixnum(x)), "/", 1, y); + mrb_get_args(mrb, "o", &y); + return mrb_float_value(mrb_to_flo(mrb, x) / mrb_to_flo(mrb, y)); } /* @@ -276,10 +121,10 @@ num_quo(mrb_state *mrb, mrb_value x) static mrb_value num_abs(mrb_state *mrb, mrb_value num) { - if (mrb_test(mrb_funcall(mrb, num, "<", 1, mrb_fixnum_value(0)))) { - return mrb_funcall(mrb, num, "-@", 0); - } - return num; + if (mrb_to_flo(mrb, num) < 0) { + return num_uminus(mrb, num); + } + return num; } /******************************************************************** @@ -291,17 +136,6 @@ num_abs(mrb_state *mrb, mrb_value num) * representation. */ -mrb_value -mrb_float_new(mrb_float d) -{ - //NEWOBJ(flt, struct RFloat); - //OBJSETUP(flt, mrb_cFloat, MRB_TT_FLOAT); - - //flt->float_value = d; - //return (mrb_value)flt; - return mrb_float_value(d); -} - /* 15.2.9.3.16(x) */ /* * call-seq: @@ -316,30 +150,30 @@ mrb_float_new(mrb_float d) static mrb_value flo_to_s(mrb_state *mrb, mrb_value flt) { - char buf[32]; - mrb_float value = mrb_float(flt); - char *p, *e; + char buf[32]; + mrb_float value = mrb_float(flt); + char *p, *e; - if (isinf(value)) - return mrb_str_new2(mrb, value < 0 ? "-Infinity" : "Infinity"); - else if(isnan(value)) - return mrb_str_new2(mrb, "NaN"); + if (isinf(value)) + return mrb_str_new2(mrb, value < 0 ? "-Infinity" : "Infinity"); + else if(isnan(value)) + return mrb_str_new2(mrb, "NaN"); - sprintf(buf, "%#.15g", value); /* ensure to print decimal point */ + sprintf(buf, "%#.15g", value); /* ensure to print decimal point */ + if (!(e = strchr(buf, 'e'))) { + e = buf + strlen(buf); + } + if (!ISDIGIT(e[-1])) { /* reformat if ended with decimal point (ex 111111111111111.) */ + sprintf(buf, "%#.14e", value); if (!(e = strchr(buf, 'e'))) { e = buf + strlen(buf); } - if (!ISDIGIT(e[-1])) { /* reformat if ended with decimal point (ex 111111111111111.) */ - sprintf(buf, "%#.14e", value); - if (!(e = strchr(buf, 'e'))) { - e = buf + strlen(buf); - } - } - p = e; - while (p[-1]=='0' && ISDIGIT(p[-2])) - p--; - memmove(p, e, strlen(e)+1); - return mrb_str_new2(mrb, buf); + } + p = e; + while (p[-1]=='0' && ISDIGIT(p[-2])) + p--; + memmove(p, e, strlen(e)+1); + return mrb_str_new2(mrb, buf); } /* 15.2.9.3.2 */ @@ -357,15 +191,7 @@ flo_minus(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - - switch (mrb_type(y)) { - case MRB_TT_FIXNUM: - return mrb_float_value(mrb_float(x) - (mrb_float)mrb_fixnum(y)); - case MRB_TT_FLOAT: - return mrb_float_value(mrb_float(x) - mrb_float(y)); - default: - return mrb_num_coerce_bin(mrb, x, y, "-"); - } + return mrb_float_value(mrb_float(x) - mrb_to_flo(mrb, y)); } /* 15.2.9.3.3 */ @@ -383,15 +209,7 @@ flo_mul(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - - switch (mrb_type(y)) { - case MRB_TT_FIXNUM: - return mrb_float_value(mrb_float(x) * (mrb_float)mrb_fixnum(y)); - case MRB_TT_FLOAT: - return mrb_float_value(mrb_float(x) * mrb_float(y)); - default: - return mrb_num_coerce_bin(mrb, x, y, "*"); - } + return mrb_float_value(mrb_float(x) * mrb_to_flo(mrb, y)); } /* 15.2.9.3.4 */ @@ -407,53 +225,28 @@ static mrb_value flo_div(mrb_state *mrb, mrb_value x) { mrb_value y; - long f_y; mrb_get_args(mrb, "o", &y); - - switch (mrb_type(y)) { - case MRB_TT_FIXNUM: - f_y = mrb_fixnum(y); - return mrb_float_value(mrb_float(x) / (mrb_float)f_y); - case MRB_TT_FLOAT: - return mrb_float_value(mrb_float(x) / mrb_float(y)); - default: - return mrb_num_coerce_bin(mrb, x, y, "/"); - } -} - -/* - * call-seq: - * float.quo(numeric) -> float - * - * Returns float / numeric. - */ -static mrb_value -flo_quo(mrb_state *mrb, mrb_value x) -{ - mrb_value y; - - mrb_get_args(mrb, "o", &y); - return mrb_funcall(mrb, x, "/", 1, y); + return mrb_float_value(mrb_float(x) / mrb_to_flo(mrb, y)); } static void flodivmod(mrb_state *mrb, mrb_float x, mrb_float y, mrb_float *divp, mrb_float *modp) { - mrb_float div, mod; - - if (y == 0.0) mrb_num_zerodiv(mrb); - mod = fmod(x, y); - if (isinf(x) && !isinf(y) && !isnan(y)) - div = x; - else - div = (x - mod) / y; - if (y*mod < 0) { - mod += y; - div -= 1.0; - } - if (modp) *modp = mod; - if (divp) *divp = div; + mrb_float div, mod; + + if (y == 0.0) mrb_num_zerodiv(mrb); + mod = fmod(x, y); + if (isinf(x) && !isinf(y) && !isnan(y)) + div = x; + else + div = (x - mod) / y; + if (y*mod < 0) { + mod += y; + div -= 1.0; + } + if (modp) *modp = mod; + if (divp) *divp = div; } /* 15.2.9.3.5 */ @@ -475,31 +268,11 @@ flo_mod(mrb_state *mrb, mrb_value x) mrb_float fy, mod; mrb_get_args(mrb, "o", &y); - switch (mrb_type(y)) { - case MRB_TT_FIXNUM: - fy = (mrb_float)mrb_fixnum(y); - break; - case MRB_TT_FLOAT: - fy = mrb_float(y); - break; - default: - return mrb_num_coerce_bin(mrb, x, y, "%"); - } - flodivmod(mrb, mrb_float(x), fy, 0, &mod); - return mrb_float_value(mod); + fy = mrb_to_flo(mrb, y); + flodivmod(mrb, mrb_float(x), fy, 0, &mod); + return mrb_float_value(mod); } -static mrb_value -flt2ival(mrb_float d) -{ - if (FIXABLE(d)) { - d = round(d); - return mrb_fixnum_value((long)d); - } - return mrb_nil_value(); -} - - /* 15.2.8.3.16 */ /* * call-seq: @@ -529,8 +302,8 @@ num_eql(mrb_state *mrb, mrb_value x) static mrb_value num_equal(mrb_state *mrb, mrb_value x, mrb_value y) { - if (mrb_obj_equal(mrb, x, y)) return mrb_true_value(); - return mrb_funcall(mrb, y, "==", 1, x); + if (mrb_obj_equal(mrb, x, y)) return mrb_true_value(); + return mrb_funcall(mrb, y, "==", 1, x); } /* 15.2.9.3.7 */ @@ -553,24 +326,18 @@ flo_eq(mrb_state *mrb, mrb_value x) volatile mrb_float a, b; mrb_get_args(mrb, "o", &y); - switch (mrb_type(y)) { - case MRB_TT_FIXNUM: - b = (mrb_float)mrb_fixnum(y); - break; - case MRB_TT_FLOAT: - b = mrb_float(y); -#if defined(_MSC_VER) && _MSC_VER < 1300 - if (isnan(b)) return mrb_false_value(); -#endif - break; - default: - return num_equal(mrb, x, y); - } - a = mrb_float(x); -#if defined(_MSC_VER) && _MSC_VER < 1300 - if (isnan(a)) return mrb_false_value(); -#endif - return (a == b)?mrb_true_value():mrb_false_value(); + switch (mrb_type(y)) { + case MRB_TT_FIXNUM: + b = (mrb_float)mrb_fixnum(y); + break; + case MRB_TT_FLOAT: + b = mrb_float(y); + break; + default: + return num_equal(mrb, x, y); + } + a = mrb_float(x); + return (a == b)?mrb_true_value():mrb_false_value(); } /* 15.2.8.3.18 */ @@ -597,16 +364,6 @@ flo_hash(mrb_state *mrb, mrb_value num) return mrb_fixnum_value(hash); } -mrb_value -mrb_flt_cmp(double a, double b) -{ - if (isnan(a) || isnan(b)) return mrb_nil_value(); - if (a == b) return mrb_fixnum_value(0); - if (a > b) return mrb_fixnum_value(1); - if (a < b) return mrb_fixnum_value(-1); - return mrb_nil_value(); -} - /* 15.2.9.3.13 */ /* * call-seq: @@ -618,7 +375,7 @@ mrb_flt_cmp(double a, double b) static mrb_value flo_to_f(mrb_state *mrb, mrb_value num) { - return num; + return num; } /* 15.2.9.3.11 */ @@ -637,13 +394,12 @@ flo_to_f(mrb_state *mrb, mrb_value num) static mrb_value flo_is_infinite_p(mrb_state *mrb, mrb_value num) { - mrb_float value = mrb_float(num); - - if (isinf(value)) { - return mrb_fixnum_value( value < 0 ? -1 : 1 ); - } + mrb_float value = mrb_float(num); - return mrb_nil_value(); + if (isinf(value)) { + return mrb_fixnum_value( value < 0 ? -1 : 1 ); + } + return mrb_nil_value(); } /* 15.2.9.3.9 */ @@ -660,17 +416,11 @@ flo_is_infinite_p(mrb_state *mrb, mrb_value num) static mrb_value flo_is_finite_p(mrb_state *mrb, mrb_value num) { - mrb_float value = mrb_float(num); - -#if HAVE_FINITE - if (!finite(value)) - return mrb_false_value(); -#else - if (isinf(value) || isnan(value)) - return mrb_false_value(); -#endif + mrb_float value = mrb_float(num); - return mrb_true_value(); + if (isinf(value) || isnan(value)) + return mrb_false_value(); + return mrb_true_value(); } /* 15.2.9.3.10 */ @@ -689,14 +439,12 @@ flo_is_finite_p(mrb_state *mrb, mrb_value num) static mrb_value flo_floor(mrb_state *mrb, mrb_value num) { - mrb_float f = floor(mrb_float(num)); - long val; + mrb_float f = floor(mrb_float(num)); - if (!FIXABLE(f)) { - return mrb_flt2big(mrb, f); - } - val = (long)f; - return mrb_fixnum_value(val); + if (!FIXABLE(f)) { + return mrb_float_value(f); + } + return mrb_fixnum_value((mrb_int)f); } /* 15.2.9.3.8 */ @@ -716,14 +464,12 @@ flo_floor(mrb_state *mrb, mrb_value num) static mrb_value flo_ceil(mrb_state *mrb, mrb_value num) { - mrb_float f = ceil(mrb_float(num)); - long val; + mrb_float f = ceil(mrb_float(num)); - if (!FIXABLE(f)) { - return mrb_flt2big(mrb, f); - } - val = (long)f; - return mrb_fixnum_value(val); + if (!FIXABLE(f)) { + return mrb_float_value(f); + } + return mrb_fixnum_value((mrb_int)f); } /* 15.2.9.3.12 */ @@ -763,40 +509,47 @@ flo_round(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value num) mrb_value nd; mrb_float number, f; int ndigits = 0, i; - long val; mrb_value *argv; int argc; mrb_get_args(mrb, "*", &argv, &argc); - if (argc /*> 0 && mrb_scan_args(argc, argv, "01", &nd) */== 1) { - nd = argv[0]; - ndigits = mrb_fixnum(nd); - } - number = mrb_float(num); - f = 1.0; - i = abs(ndigits); - while (--i >= 0) - f = f*10.0; - - if (isinf(f)) { - if (ndigits < 0) number = 0; + if (argc == 1) { + nd = argv[0]; + ndigits = mrb_fixnum(nd); + } + number = mrb_float(num); + f = 1.0; + i = abs(ndigits); + while (--i >= 0) + f = f*10.0; + + if (isinf(f)) { + if (ndigits < 0) number = 0; + } + else { + mrb_float d; + + if (ndigits < 0) number /= f; + else number *= f; + + /* home-made inline implementation of round(3) */ + if (number > 0.0) { + d = floor(number); + number = d + (number - d >= 0.5); } - else { - if (ndigits < 0) number /= f; - else number *= f; - number = round(number); - if (ndigits < 0) number *= f; - else number /= f; + else if (number < 0.0) { + d = ceil(number); + number = d - (d - number >= 0.5); } - if (ndigits > 0) return mrb_float_value(number); + number = round(number); + if (ndigits < 0) number *= f; + else number /= f; + } - if (!FIXABLE(number)) { - return mrb_flt2big(mrb, number); - } - val = (long)number; - return mrb_fixnum_value(val); + if (ndigits > 0) return mrb_float_value(number); + return mrb_fixnum_value((mrb_int)number); } /* 15.2.9.3.14 */ @@ -813,17 +566,15 @@ flo_round(mrb_state *mrb, /*int argc, mrb_value *argv,*/ mrb_value num) static mrb_value flo_truncate(mrb_state *mrb, mrb_value num) { - mrb_float f = mrb_float(num); - long val; + mrb_float f = mrb_float(num); - if (f > 0.0) f = floor(f); - if (f < 0.0) f = ceil(f); + if (f > 0.0) f = floor(f); + if (f < 0.0) f = ceil(f); - if (!FIXABLE(f)) { - return mrb_flt2big(mrb, f); - } - val = (long)f; - return mrb_fixnum_value(val); + if (!FIXABLE(f)) { + return mrb_float_value(f); + } + return mrb_fixnum_value((mrb_int)f); } /* 15.2.8.3.17 */ @@ -842,7 +593,7 @@ flo_truncate(mrb_state *mrb, mrb_value num) static mrb_value num_floor(mrb_state *mrb, mrb_value num) { - return flo_floor(mrb, mrb_Float(mrb, num)); + return flo_floor(mrb, mrb_Float(mrb, num)); } /* 15.2.8.3.20 */ @@ -857,96 +608,9 @@ num_floor(mrb_state *mrb, mrb_value num) */ static mrb_value -num_round(mrb_state *mrb, /*int argc, mrb_value* argv,*/ mrb_value num) -{ - return flo_round(mrb, /*argc, argv,*/ mrb_Float(mrb, num)); -} - -SIGNED_VALUE -mrb_num2long(mrb_state *mrb, mrb_value val) +num_round(mrb_state *mrb, mrb_value num) { - again: - if (mrb_nil_p(val)) { - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion from nil to integer"); - } - - if (FIXNUM_P(val)) return mrb_fixnum(val); - - switch (mrb_type(val)) { - case MRB_TT_FLOAT: - if (mrb_float(val) <= (mrb_float)LONG_MAX - && mrb_float(val) >= (mrb_float)LONG_MIN) { - return (SIGNED_VALUE)(mrb_float(val)); - } - else { - char buf[24]; - char *s; - - snprintf(buf, sizeof(buf), "%-.10g", mrb_float(val)); - if ((s = strchr(buf, ' ')) != 0) *s = '\0'; - mrb_raise(mrb, E_RANGE_ERROR, "float %s out of range of integer", buf); - } - - default: - val = mrb_to_int(mrb, val); - goto again; - } -} - -mrb_value -mrb_num2ulong(mrb_state *mrb, mrb_value val) -{ - again: - if (mrb_nil_p(val)) { - mrb_raise(mrb, E_TYPE_ERROR, "no implicit conversion from nil to integer"); - } - - if (FIXNUM_P(val)) return val; /* this is FIX2LONG, inteneded */ - - switch (mrb_type(val)) { - case MRB_TT_FLOAT: - if (mrb_float(val) <= (mrb_float)LONG_MAX - && mrb_float(val) >= (mrb_float)LONG_MIN) { - return mrb_fixnum_value(mrb_float(val)); - } - else { - char buf[24]; - char *s; - - snprintf(buf, sizeof(buf), "%-.10g", mrb_float(val)); - if ((s = strchr(buf, ' ')) != 0) *s = '\0'; - mrb_raise(mrb, E_RANGE_ERROR, "float %s out of range of integer", buf); - } - - default: - val = mrb_to_int(mrb, val); - goto again; - } -} - -long -mrb_num2int(mrb_state *mrb, mrb_value val) -{ - return mrb_num2long(mrb, val); -} - -long -mrb_fix2int(mrb_value val) -{ - return mrb_fixnum(val); -} - -mrb_value -mrb_num2fix(mrb_state *mrb, mrb_value val) -{ - long v; - - if (FIXNUM_P(val)) return val; - - v = mrb_num2long(mrb, val); - if (!FIXABLE(v)) - mrb_raise(mrb, E_RANGE_ERROR, "integer %ld out of range of fixnum", v); - return mrb_fixnum_value(v); + return flo_round(mrb, mrb_Float(mrb, num)); } /* @@ -977,7 +641,7 @@ mrb_num2fix(mrb_state *mrb, mrb_value val) static mrb_value int_to_i(mrb_state *mrb, mrb_value num) { - return num; + return num; } /* 15.2.8.3.21 */ @@ -995,8 +659,7 @@ int_to_i(mrb_state *mrb, mrb_value num) static mrb_value fix_succ(mrb_state *mrb, mrb_value num) { - long i = mrb_fixnum(num) + 1; - return mrb_fixnum_value(i); + return mrb_fixnum_value(mrb_fixnum(num)+1); } /* 15.2.8.3.19 */ @@ -1013,43 +676,11 @@ fix_succ(mrb_state *mrb, mrb_value num) static mrb_value int_succ(mrb_state *mrb, mrb_value num) { - if (FIXNUM_P(num)) { - long i = mrb_fixnum(num) + 1; - return mrb_fixnum_value(i); - } - return mrb_funcall(mrb, num, "+", 1, mrb_fixnum_value(1)); + if (FIXNUM_P(num)) return fix_succ(mrb, num); + return mrb_funcall(mrb, num, "+", 1, mrb_fixnum_value(1)); } -mrb_value -rb_fix2str(mrb_state *mrb, mrb_value x, int base) -{ - extern const char ruby_digitmap[]; - char buf[sizeof(mrb_int)*CHAR_BIT + 2], *b = buf + sizeof buf; - long val = mrb_fixnum(x); - int neg = 0; - - if (base < 2 || 36 < base) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid radix %d", base); - } - if (val == 0) { - return mrb_str_new_cstr(mrb, "0"); - } - if (val < 0) { - val = -val; - neg = 1; - } - *--b = '\0'; - do { - *--b = ruby_digitmap[(int)(val % base)]; - } while (val /= base); - if (neg) { - *--b = '-'; - } - - return mrb_str_new_cstr(mrb, b); -} - -#define SQRT_LONG_MAX ((SIGNED_VALUE)1<<((sizeof(intptr_t)*CHAR_BIT-1)/2)) +#define SQRT_LONG_MAX ((SIGNED_VALUE)1<<((sizeof(mrb_int)*CHAR_BIT-1)/2)) /*tests if N*N would overflow*/ #define FIT_SQRT_LONG(n) (((n)<SQRT_LONG_MAX)&&((n)>=-SQRT_LONG_MAX)) @@ -1067,102 +698,54 @@ static mrb_value fix_mul(mrb_state *mrb, mrb_value x) { mrb_value y; + mrb_int a; mrb_get_args(mrb, "o", &y); - if (FIXNUM_P(y)) { -#ifdef __HP_cc -/* avoids an optimization bug of HP aC++/ANSI C B3910B A.06.05 [Jul 25 2005] */ - volatile -#endif - long a, b; - long c; - mrb_value r; - - a = mrb_fixnum(x); - b = mrb_fixnum(y); - - if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b)) - return mrb_fixnum_value(a*b); - c = a * b; - r = mrb_fixnum_value(c); - - if (a == 0) return x; - if (mrb_fixnum(r) != c || c/a != b) { - //r = mrb_big_mul(mrb_int2big(a), mrb_int2big(b)); - r = mrb_fixnum_value(a*b); - } - return r; - } - switch (mrb_type(y)) { - case MRB_TT_FLOAT: - return mrb_float_value((mrb_float)mrb_fixnum(x) * mrb_float(y)); - default: - return mrb_num_coerce_bin(mrb, x, y, "*"); - } -} + a = mrb_fixnum(x); + if (FIXNUM_P(y)) { + mrb_int b, c; + mrb_value r; -static void -fixdivmod(mrb_state *mrb, long x, long y, long *divp, long *modp) -{ - long div, mod; - - if (y == 0) mrb_num_zerodiv(mrb); - if (y < 0) { - if (x < 0) - div = -x / -y; - else - div = - (x / -y); - } - else { - if (x < 0) - div = - (-x / y); - else - div = x / y; - } - mod = x - div*y; - if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) { - mod += y; - div -= 1; + b = mrb_fixnum(y); + if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b)) + return mrb_fixnum_value(a*b); + c = a * b; + r = mrb_fixnum_value(c); + + if (a == 0) return x; + if (mrb_fixnum(r) != c || c/a != b) { + r = mrb_float_value((mrb_float)a*(mrb_float)b); } - if (divp) *divp = div; - if (modp) *modp = mod; + return r; + } + return mrb_float_value((mrb_float)a * mrb_to_flo(mrb, y)); } -mrb_value rb_big_fdiv(mrb_value x, mrb_value y); - -//mrb_value mrb_rational_reciprocal(mrb_value x); - -static mrb_value -fix_divide(mrb_state *mrb, mrb_value x, mrb_value y, char* op) +static void +fixdivmod(mrb_state *mrb, mrb_int x, mrb_int y, mrb_int *divp, mrb_int *modp) { - if (FIXNUM_P(y)) { - long div; + mrb_int div, mod; - fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, 0); - return mrb_fixnum_value(div); - } - switch (mrb_type(y)) { - case MRB_TT_FLOAT: - { - mrb_float div; - - if (*op == '/') { - div = (mrb_float)mrb_fixnum(x) / mrb_float(y); - return mrb_float_value(div); - } - else { - if (mrb_float(y) == 0) mrb_num_zerodiv(mrb); - div = (mrb_float)mrb_fixnum(x) / mrb_float(y); - return mrb_flt2big(mrb, floor(div)); - } - } - //case MRB_TT_RATIONAL: - // if (op == '/' && mrb_fixnum(x) == 1) - // return mrb_rational_reciprocal(y); - /* fall through */ - default: - return mrb_num_coerce_bin(mrb, x, y, op); - } + if (y == 0) mrb_num_zerodiv(mrb); + if (y < 0) { + if (x < 0) + div = -x / -y; + else + div = - (x / -y); + } + else { + if (x < 0) + div = - (-x / y); + else + div = x / y; + } + mod = x - div*y; + if ((mod < 0 && y > 0) || (mod > 0 && y < 0)) { + mod += y; + div -= 1; + } + if (divp) *divp = div; + if (modp) *modp = mod; } /* 15.2.8.3.4 */ @@ -1179,9 +762,18 @@ static mrb_value fix_div(mrb_state *mrb, mrb_value x) { mrb_value y; + mrb_int a; + mrb_get_args(mrb, "o", &y); - return fix_divide(mrb, x, y, "/"); + a = mrb_fixnum(x); + if (FIXNUM_P(y)) { + mrb_int div; + + fixdivmod(mrb, a, mrb_fixnum(y), &div, 0); + return mrb_fixnum_value(div); + } + return mrb_float_value((mrb_float)a / mrb_to_flo(mrb, y)); } /* 15.2.8.3.5 */ @@ -1198,25 +790,23 @@ static mrb_value fix_mod(mrb_state *mrb, mrb_value x) { mrb_value y; + mrb_int a; + mrb_get_args(mrb, "o", &y); - if (FIXNUM_P(y)) { - long mod; + a = mrb_fixnum(x); + if (FIXNUM_P(y)) { + mrb_int mod; - fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), 0, &mod); - return mrb_fixnum_value(mod); - } - switch (mrb_type(y)) { - case MRB_TT_FLOAT: - { - mrb_float mod; + fixdivmod(mrb, a, mrb_fixnum(y), 0, &mod); + return mrb_fixnum_value(mod); + } + else { + mrb_float mod; - flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_float(y), 0, &mod); - return mrb_float_value(mod); - } - default: - return mrb_num_coerce_bin(mrb, x, y, "%"); - } + flodivmod(mrb, (mrb_float)a, mrb_to_flo(mrb, y), 0, &mod); + return mrb_float_value(mod); + } } /* @@ -1231,27 +821,21 @@ fix_divmod(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - if (FIXNUM_P(y)) { - long div, mod; + if (FIXNUM_P(y)) { + mrb_int div, mod; - fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod); + fixdivmod(mrb, mrb_fixnum(x), mrb_fixnum(y), &div, &mod); + return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod)); + } + else { + mrb_float div, mod; + mrb_value a, b; - return mrb_assoc_new(mrb, mrb_fixnum_value(div), mrb_fixnum_value(mod)); - } - switch (mrb_type(y)) { - case MRB_TT_FLOAT: - { - mrb_float div, mod; - volatile mrb_value a, b; - - flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_float(y), &div, &mod); - a = flt2ival(div); - b = mrb_float_value(mod); - return mrb_assoc_new(mrb, a, b); - } - default: - return mrb_num_coerce_bin(mrb, x, y, "divmod"); - } + flodivmod(mrb, (mrb_float)mrb_fixnum(x), mrb_to_flo(mrb, y), &div, &mod); + a = mrb_float_value((mrb_int)div); + b = mrb_float_value(mod); + return mrb_assoc_new(mrb, a, b); + } } /* 15.2.8.3.7 */ @@ -1272,14 +856,16 @@ fix_equal(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - if (mrb_obj_equal(mrb, x, y)) return mrb_true_value(); - if (FIXNUM_P(y)) return mrb_false_value(); - switch (mrb_type(y)) { - case MRB_TT_FLOAT: - return (mrb_float)mrb_fixnum(x) == mrb_float(y) ? mrb_true_value() : mrb_false_value(); - default: - return num_equal(mrb, x, y); - } + if (mrb_obj_equal(mrb, x, y)) return mrb_true_value(); + switch (mrb_type(y)) { + case MRB_TT_FLOAT: + if ((mrb_float)mrb_fixnum(x) == mrb_float(y)) + return mrb_true_value(); + /* fall through */ + case MRB_TT_FIXNUM: + default: + return mrb_false_value(); + } } /* 15.2.8.3.8 */ @@ -1296,7 +882,7 @@ fix_equal(mrb_state *mrb, mrb_value x) static mrb_value fix_rev(mrb_state *mrb, mrb_value num) { - long val = mrb_fixnum(num); + mrb_int val = mrb_fixnum(num); val = ~val; return mrb_fixnum_value(val); @@ -1326,15 +912,9 @@ static mrb_value fix_and(mrb_state *mrb, mrb_value x) { mrb_value y; - long val; + mrb_int val; mrb_get_args(mrb, "o", &y); - //if (!FIXNUM_P(y = bit_coerce(mrb, y))) { - // return mrb_big_and(y, x); - //} - if (mrb_type(y) == MRB_TT_FLOAT) { - mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer"); - } y = bit_coerce(mrb, y); val = mrb_fixnum(x) & mrb_fixnum(y); return mrb_fixnum_value(val); @@ -1352,15 +932,9 @@ static mrb_value fix_or(mrb_state *mrb, mrb_value x) { mrb_value y; - long val; + mrb_int val; mrb_get_args(mrb, "o", &y); - //if (!FIXNUM_P(y = bit_coerce(mrb, y))) { - // return mrb_big_or(y, x); - //} - if (mrb_type(y) == MRB_TT_FLOAT) { - mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer"); - } y = bit_coerce(mrb, y); val = mrb_fixnum(x) | mrb_fixnum(y); return mrb_fixnum_value(val); @@ -1378,22 +952,16 @@ static mrb_value fix_xor(mrb_state *mrb, mrb_value x) { mrb_value y; - long val; + mrb_int val; mrb_get_args(mrb, "o", &y); - //if (!FIXNUM_P(y = bit_coerce(mrb, y))) { - // return mrb_big_xor(y, x); - //} - if (mrb_type(y) == MRB_TT_FLOAT) { - mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer"); - } y = bit_coerce(mrb, y); val = mrb_fixnum(x) ^ mrb_fixnum(y); return mrb_fixnum_value(val); } -static mrb_value fix_lshift(mrb_state *mrb, long, unsigned long); -static mrb_value fix_rshift(long, unsigned long); +static mrb_value fix_lshift(mrb_state *mrb, mrb_int, unsigned long); +static mrb_value fix_rshift(mrb_int, unsigned long); /* 15.2.8.3.12 */ /* @@ -1407,15 +975,11 @@ static mrb_value mrb_fix_lshift(mrb_state *mrb, mrb_value x) { mrb_value y; - long val, width; + mrb_int val, width; mrb_get_args(mrb, "o", &y); val = mrb_fixnum(x); - //if (!FIXNUM_P(y)) - // return mrb_big_lshift(mrb_int2big(val), y); - if (mrb_type(y) == MRB_TT_FLOAT) { - mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer"); - } + y = bit_coerce(mrb, y); width = mrb_fixnum(y); if (width < 0) return fix_rshift(val, (unsigned long)-width); @@ -1423,11 +987,12 @@ mrb_fix_lshift(mrb_state *mrb, mrb_value x) } static mrb_value -fix_lshift(mrb_state *mrb, long val, unsigned long width) +fix_lshift(mrb_state *mrb, mrb_int val, unsigned long width) { - if (width > (sizeof(intptr_t)*CHAR_BIT-1) - || ((unsigned long)abs(val))>>(sizeof(intptr_t)*CHAR_BIT-1-width) > 0) { - mrb_raise(mrb, E_RANGE_ERROR, "width(%d) > (sizeof(intptr_t)*CHAR_BIT-1)", width); + if (width > (sizeof(mrb_int)*CHAR_BIT-1) + || ((unsigned long)abs(val))>>(sizeof(mrb_int)*CHAR_BIT-1-width) > 0) { + mrb_raise(mrb, E_RANGE_ERROR, "width(%d) > (%d:sizeof(mrb_int)*CHAR_BIT-1)", width, + sizeof(mrb_int)*CHAR_BIT-1); } val = val << width; return mrb_fixnum_value(val); @@ -1445,13 +1010,12 @@ static mrb_value mrb_fix_rshift(mrb_state *mrb, mrb_value x) { mrb_value y; - long i, val; + mrb_int i, val; mrb_get_args(mrb, "o", &y); - val = mrb_fixnum(x); - //if (!FIXNUM_P(y)) - // return mrb_big_rshift(mrb_int2big(val), y); - i = mrb_fixnum(y); + val = mrb_fixnum(x); + y = bit_coerce(mrb, y); + i = mrb_fixnum(y); if (i == 0) return x; if (i < 0) return fix_lshift(mrb, val, (unsigned long)-i); @@ -1459,9 +1023,9 @@ mrb_fix_rshift(mrb_state *mrb, mrb_value x) } static mrb_value -fix_rshift(long val, unsigned long i) +fix_rshift(mrb_int val, unsigned long i) { - if (i >= sizeof(long)*CHAR_BIT-1) { + if (i >= sizeof(mrb_int)*CHAR_BIT-1) { if (val < 0) return mrb_fixnum_value(-1); return mrb_fixnum_value(0); } @@ -1523,9 +1087,6 @@ fix_to_f(mrb_state *mrb, mrb_value num) static mrb_int flt2big(mrb_state *mrb, float d) { - //long i = 0; - //BDIGIT c; - //BDIGIT *digits; mrb_int z; if (isinf(d)) { @@ -1587,41 +1148,6 @@ mrb_fixnum_minus(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(x - y); } -/* 15.2.8.3.6 */ -/* - * call-seq: - * self.i <=> other.i => -1, 0, +1 - * < => -1 - * = => 0 - * > => +1 - * Comparison---Returns -1, 0, or +1 depending on whether <i>fix</i> is - * less than, equal to, or greater than <i>numeric</i>. This is the - * basis for the tests in <code>Comparable</code>. - */ -static mrb_value -mrb_fixnum_cmp(mrb_state *mrb, mrb_value self) -{ - mrb_int x, y; - mrb_value vy; - - mrb_get_args(mrb, "o", &vy); - if (FIXNUM_P(vy)) { - x = mrb_fixnum(self); - y = mrb_fixnum(vy); - DEBUG(printf("%d <=> %d\n", x, y)); - if (x > y) - return mrb_fixnum_value(1); - else if (x < y) - return mrb_fixnum_value(-1); - else - return mrb_fixnum_value(0); - } - else { - return mrb_num_coerce_cmp(mrb, self, vy, "<=>"); - } - -} - /* 15.2.8.3.29 (x) */ /* * call-seq: @@ -1635,7 +1161,7 @@ mrb_value mrb_fix2str(mrb_state *mrb, mrb_value x, int base) { char buf[64], *b = buf + sizeof buf; - long val = mrb_fixnum(x); + mrb_int val = mrb_fixnum(x); int neg = 0; if (base < 2 || 36 < base) { @@ -1713,21 +1239,24 @@ mrb_fixnum_to_s(mrb_state *mrb, mrb_value self) /* fix_to_s */ * basis for the tests in <code>Comparable</code>. */ static mrb_value -mrb_float_cmp(mrb_state *mrb, mrb_value self) +num_cmp(mrb_state *mrb, mrb_value self) { - mrb_value vy; + mrb_value other; mrb_float x, y; - x = mrb_float(self); - mrb_get_args(mrb, "o", &vy); - if (FIXNUM_P(vy)) { - y = (mrb_float)mrb_fixnum(vy); - } - else { - y = mrb_float(vy); + mrb_get_args(mrb, "o", &other); + + x = mrb_to_flo(mrb, self); + switch (mrb_type(other)) { + case MRB_TT_FIXNUM: + y = (mrb_float)mrb_fixnum(other); + break; + case MRB_TT_FLOAT: + y = mrb_float(other); + break; + default: + return mrb_nil_value(); } - - DEBUG(printf("%f <=> %f\n", x, y)); if (x > y) return mrb_fixnum_value(1); else { @@ -1767,8 +1296,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, "+@", num_uplus, ARGS_REQ(1)); /* 15.2.7.4.1 */ mrb_define_method(mrb, numeric, "-@", num_uminus, ARGS_REQ(1)); /* 15.2.7.4.2 */ mrb_define_method(mrb, numeric, "abs", num_abs, ARGS_NONE()); /* 15.2.7.4.3 */ - mrb_define_method(mrb, numeric, "coerce", num_coerce, ARGS_REQ(1)); /* 15.2.7.4.4 */ mrb_define_method(mrb, numeric, "quo", num_quo, ARGS_REQ(1)); /* 15.2.7.4.5 (x) */ + mrb_define_method(mrb, numeric, "<=>", num_cmp, ARGS_REQ(1)); /* 15.2.9.3.6 */ /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); @@ -1776,10 +1305,10 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fixnum, "+", mrb_fixnum_plus, ARGS_REQ(1)); /* 15.2.8.3.1 */ mrb_define_method(mrb, fixnum, "-", mrb_fixnum_minus, ARGS_REQ(1)); /* 15.2.8.3.2 */ + mrb_define_method(mrb, fixnum, "-@", fix_uminus, ARGS_REQ(1)); /* 15.2.7.4.2 */ mrb_define_method(mrb, fixnum, "*", fix_mul, ARGS_REQ(1)); /* 15.2.8.3.3 */ mrb_define_method(mrb, fixnum, "/", fix_div, ARGS_REQ(1)); /* 15.2.8.3.4 */ mrb_define_method(mrb, fixnum, "%", fix_mod, ARGS_REQ(1)); /* 15.2.8.3.5 */ - mrb_define_method(mrb, fixnum, "<=>", mrb_fixnum_cmp, ARGS_REQ(1)); /* 15.2.8.3.6 */ mrb_define_method(mrb, fixnum, "==", fix_equal, ARGS_REQ(1)); /* 15.2.8.3.7 */ mrb_define_method(mrb, fixnum, "~", fix_rev, ARGS_NONE()); /* 15.2.8.3.8 */ mrb_define_method(mrb, fixnum, "&", fix_and, ARGS_REQ(1)); /* 15.2.8.3.9 */ @@ -1809,7 +1338,6 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "*", flo_mul, ARGS_REQ(1)); /* 15.2.9.3.3 */ mrb_define_method(mrb, fl, "/", flo_div, ARGS_REQ(1)); /* 15.2.9.3.4 */ mrb_define_method(mrb, fl, "%", flo_mod, ARGS_REQ(1)); /* 15.2.9.3.5 */ - mrb_define_method(mrb, fl, "<=>", mrb_float_cmp, ARGS_REQ(1)); /* 15.2.9.3.6 */ mrb_define_method(mrb, fl, "==", flo_eq, ARGS_REQ(1)); /* 15.2.9.3.7 */ mrb_define_method(mrb, fl, "ceil", flo_ceil, ARGS_NONE()); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_is_finite_p, ARGS_NONE()); /* 15.2.9.3.9 */ @@ -1823,5 +1351,5 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "to_s", flo_to_s, ARGS_NONE()); /* 15.2.9.3.16(x) */ //mrb_define_method(mrb, fl, "<", flo_lt, ARGS_REQ(1)); /* 15.2.9.3.17(x) */ //mrb_define_method(mrb, fl, ">", flo_gt, ARGS_REQ(1)); /* 15.2.9.3.18(x) */ - mrb_define_method(mrb, fl, "quo", flo_quo, ARGS_REQ(1)); /* 15.2.9.3.19(x) */ + mrb_define_method(mrb, fl, "quo", flo_div, ARGS_REQ(1)); /* 15.2.9.3.19(x) */ } |
