summaryrefslogtreecommitdiffhomepage
path: root/src/numeric.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/numeric.c')
-rw-r--r--src/numeric.c30
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 */