diff options
Diffstat (limited to 'src/numeric.c')
| -rw-r--r-- | src/numeric.c | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/src/numeric.c b/src/numeric.c index 2140a8411..5f23b2461 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -19,9 +19,11 @@ #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) #define FLO_MAX_DIGITS 7 +#define FLO_MAX_SIGN_LENGTH 3 #define FLO_EPSILON FLT_EPSILON #else #define FLO_MAX_DIGITS 14 +#define FLO_MAX_SIGN_LENGTH 10 #define FLO_EPSILON DBL_EPSILON #endif @@ -130,6 +132,7 @@ mrb_flo_to_str(mrb_state *mrb, mrb_float flo) mrb_bool e = FALSE; char s[48]; char *c = &s[0]; + int length = 0; if (signbit(n)) { n = -n; @@ -147,11 +150,36 @@ mrb_flo_to_str(mrb_state *mrb, mrb_float flo) else { exp = 0; } + + /* preserve significands */ + if (exp < 0) { + int i, beg = -1, end = 0; + double f = n; + double fd = 0; + for (i = 0; i < FLO_MAX_DIGITS; ++i) { + f = (f - fd) * 10.0; + fd = floor(f + FLO_EPSILON); + if (fd != 0) { + if (beg < 0) beg = i; + end = i + 1; + } + } + if (beg >= 0) length = end - beg; + if (length > FLO_MAX_SIGN_LENGTH) length = FLO_MAX_SIGN_LENGTH; + } - if ((exp < 0 ? -exp : exp) >= FLO_MAX_DIGITS) { + if (abs(exp) + length >= FLO_MAX_DIGITS) { /* exponent representation */ e = TRUE; n = n / pow(10.0, exp); + if (isinf(n)) { + if (s < c) { /* s[0] == '-' */ + return mrb_str_new_lit(mrb, "-0.0"); + } + else { + return mrb_str_new_lit(mrb, "0.0"); + } + } } else { /* un-exponent (normal) representation */ |
