diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2019-01-14 19:13:09 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2019-01-14 19:13:09 +0900 |
| commit | 348526e1add796cd8b7b6dda2889ef5627e398c5 (patch) | |
| tree | 19d9c28bbe8e925b1b27986fbc376693dba5cd54 /src/numeric.c | |
| parent | c1b92f88a210d018b653dc9865fe5375cf118a61 (diff) | |
| parent | 0e04c46261eb9d5193f21d423f5d00f1910a460a (diff) | |
| download | mruby-348526e1add796cd8b7b6dda2889ef5627e398c5.tar.gz mruby-348526e1add796cd8b7b6dda2889ef5627e398c5.zip | |
Merge pull request #4225 from shuujii/improve-compatibility-to-cruby-for-float-to_s
Improve compatibility to CRuby for `Float#to_s`
Diffstat (limited to 'src/numeric.c')
| -rw-r--r-- | src/numeric.c | 48 |
1 files changed, 44 insertions, 4 deletions
diff --git a/src/numeric.c b/src/numeric.c index 089cc744d..fc8460300 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 @@ -177,10 +178,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; + + insert_dot_zero: + begp = RSTRING_PTR(str); + len = RSTRING_LEN(str); + for (char *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 */ |
