diff options
Diffstat (limited to 'src/numeric.c')
| -rw-r--r-- | src/numeric.c | 95 |
1 files changed, 76 insertions, 19 deletions
diff --git a/src/numeric.c b/src/numeric.c index 3624831cc..101b338de 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -10,6 +10,7 @@ #endif #include <limits.h> #include <stdlib.h> +#include <string.h> #include <mruby.h> #include <mruby/array.h> @@ -23,9 +24,9 @@ #define floor(f) floorf(f) #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) -#define MRB_FLO_TO_STR_FMT "%.8g" +#define FLO_TO_STR_PREC 8 #else -#define MRB_FLO_TO_STR_FMT "%.16g" +#define FLO_TO_STR_PREC 16 #endif #endif @@ -153,6 +154,22 @@ num_div(mrb_state *mrb, mrb_value x) #endif } +static mrb_value +num_coerce_step_counter(mrb_state *mrb, mrb_value self) +{ + mrb_value counter = self, num, step; + + mrb_get_args(mrb, "oo", &num, &step); + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(self) || mrb_float_p(num) || mrb_float_p(step)) { + counter = mrb_funcall(mrb, counter, "to_f", 0); + } +#endif + + return counter; +} + #ifndef MRB_WITHOUT_FLOAT /******************************************************************** * @@ -177,10 +194,49 @@ num_div(mrb_state *mrb, mrb_value x) static mrb_value flo_to_s(mrb_state *mrb, mrb_value flt) { - if (isnan(mrb_float(flt))) { + mrb_float f = mrb_float(flt); + + if (isinf(f)) { + return f < 0 ? mrb_str_new_lit(mrb, "-Infinity") + : mrb_str_new_lit(mrb, "Infinity"); + } + else if (isnan(f)) { return mrb_str_new_lit(mrb, "NaN"); } - return mrb_float_to_str(mrb, flt, MRB_FLO_TO_STR_FMT); + else { + char fmt[] = "%." MRB_STRINGIZE(FLO_TO_STR_PREC) "g"; + mrb_value str = mrb_float_to_str(mrb, flt, fmt); + mrb_int len; + char *begp, *p, *endp; + + insert_dot_zero: + begp = RSTRING_PTR(str); + len = RSTRING_LEN(str); + for (p = begp, endp = p + len; p < endp; ++p) { + if (*p == '.') { + return str; + } + else if (*p == 'e') { + ptrdiff_t e_pos = p - begp; + mrb_str_cat(mrb, str, ".0", 2); + p = RSTRING_PTR(str) + e_pos; + memmove(p + 2, p, len - e_pos); + memcpy(p, ".0", 2); + return str; + } + } + + if (FLO_TO_STR_PREC + (begp[0] == '-') <= len) { + --fmt[sizeof(fmt) - 3]; /* %.16g(%.8g) -> %.15g(%.7g) */ + str = mrb_float_to_str(mrb, flt, fmt); + goto insert_dot_zero; + } + else { + mrb_str_cat(mrb, str, ".0", 2); + } + + return str; + } } /* 15.2.9.3.2 */ @@ -313,7 +369,7 @@ flo_eql(mrb_state *mrb, mrb_value x) mrb_get_args(mrb, "o", &y); if (!mrb_float_p(y)) return mrb_false_value(); - return mrb_bool_value(mrb_float(x) == (mrb_float)mrb_fixnum(y)); + return mrb_bool_value(mrb_float(x) == mrb_float(y)); } /* 15.2.9.3.7 */ @@ -454,7 +510,7 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) } static mrb_value -flo_lshift(mrb_state *mrb, mrb_value x) +flo_rshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -463,7 +519,7 @@ flo_lshift(mrb_state *mrb, mrb_value x) } static mrb_value -flo_rshift(mrb_state *mrb, mrb_value x) +flo_lshift(mrb_state *mrb, mrb_value x) { mrb_int width; @@ -1150,7 +1206,7 @@ fix_to_f(mrb_state *mrb, mrb_value num) * (in particular infinite or NaN) * to numerical classes which don't support them. * - * Float::INFINITY.to_r + * Float::INFINITY.to_i * * <em>raises the exception:</em> * @@ -1169,17 +1225,12 @@ mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) else { mrb_float d = mrb_float(x); - if (isinf(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, d < 0 ? "-Infinity" : "Infinity"); - } - if (isnan(d)) { - mrb_raise(mrb, E_FLOATDOMAIN_ERROR, "NaN"); - } + mrb_check_num_exact(mrb, d); if (FIXABLE_FLOAT(d)) { z = (mrb_int)d; } else { - mrb_raisef(mrb, E_ARGUMENT_ERROR, "number (%S) too big for integer", x); + mrb_raisef(mrb, E_RANGE_ERROR, "number (%S) too big for integer", x); } } return mrb_fixnum_value(z); @@ -1487,11 +1538,13 @@ flo_plus(mrb_state *mrb, mrb_value x) void mrb_init_numeric(mrb_state *mrb) { - struct RClass *numeric, *integer, *fixnum; + struct RClass *numeric, *integer, *fixnum, *integral; #ifndef MRB_WITHOUT_FLOAT struct RClass *fl; #endif + integral = mrb_define_module(mrb, "Integral"); + /* Numeric Class */ numeric = mrb_define_class(mrb, "Numeric", mrb->object_class); /* 15.2.7 */ @@ -1505,12 +1558,14 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, numeric, ">=", num_ge, MRB_ARGS_REQ(1)); mrb_define_method(mrb, numeric, "finite?", num_finite_p, MRB_ARGS_NONE()); mrb_define_method(mrb, numeric, "infinite?",num_infinite_p, MRB_ARGS_NONE()); + mrb_define_method(mrb, numeric, "__coerce_step_counter", num_coerce_step_counter, MRB_ARGS_REQ(2)); /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM); mrb_undef_class_method(mrb, integer, "new"); mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ + mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ @@ -1553,8 +1608,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, ">>", flo_rshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "<<", flo_lshift, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ @@ -1562,6 +1617,7 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ + mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ @@ -1576,6 +1632,7 @@ mrb_init_numeric(mrb_state *mrb) #ifdef NAN mrb_define_const(mrb, fl, "NAN", mrb_float_value(mrb, NAN)); #endif + + mrb_include_module(mrb, fl, integral); #endif - mrb_define_module(mrb, "Integral"); } |
