diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-05-13 04:30:07 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-05-13 04:30:07 +0000 |
commit | cf32125cffac638fa0cb679585767ff2990603fa (patch) | |
tree | bb53f8488775ad4cde135bc35ca21fc16f9b40c5 /numeric.c | |
parent | 04daf205b6e6578017a1e107891235890f819590 (diff) |
* marshal.c (w_float): use minimal representation.
* numeric.c (ruby_dbl2cstr): split from rb_float_new.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@27774 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 84 |
1 files changed, 43 insertions, 41 deletions
@@ -545,6 +545,8 @@ rb_float_new(double d) return (VALUE)flt; } +int ruby_dbl2cstr(double value, char *buf, int size); + /* * call-seq: * flt.to_s -> string @@ -558,70 +560,70 @@ rb_float_new(double d) static VALUE flo_to_s(VALUE flt) { - char *ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve); enum {decimal_mant = DBL_MANT_DIG-DBL_DIG}; enum {float_dig = DBL_DIG+1}; char buf[float_dig + (decimal_mant + CHAR_BIT - 1) / CHAR_BIT + 10]; double value = RFLOAT_VALUE(flt); - VALUE s; - char *p, *e; - int sign, decpt, digs; if (isinf(value)) return rb_usascii_str_new2(value < 0 ? "-Infinity" : "Infinity"); else if (isnan(value)) return rb_usascii_str_new2("NaN"); + return rb_usascii_str_new(buf, ruby_dbl2cstr(value, buf, (int)sizeof(buf))); +} + +int +ruby_dbl2cstr(double value, char *buf, int size) +{ + char *ruby_dtoa(double d_, int mode, int ndigits, int *decpt, int *sign, char **rve); + char *p, *e; + int sign, decpt, digs; + if (size <= 0) return 0; p = ruby_dtoa(value, 0, 0, &decpt, &sign, &e); - s = sign ? rb_usascii_str_new_cstr("-") : rb_usascii_str_new(0, 0); - if ((digs = (int)(e - p)) >= (int)sizeof(buf)) digs = (int)sizeof(buf) - 1; - memcpy(buf, p, digs); - xfree(p); - if (decpt > 0) { - if (decpt < digs) { - memmove(buf + decpt + 1, buf + decpt, digs - decpt); - buf[decpt] = '.'; - rb_str_cat(s, buf, digs + 1); - } - else if (decpt - digs < float_dig) { - long len; - char *ptr; - rb_str_cat(s, buf, digs); - rb_str_resize(s, (len = RSTRING_LEN(s)) + decpt - digs + 2); - ptr = RSTRING_PTR(s) + len; - if (decpt > digs) { - memset(ptr, '0', decpt - digs); - ptr += decpt - digs; + if (sign) *buf++ = '-', --size; + if ((digs = (int)(e - p)) >= size) digs = size - 1; + if (decpt > -4 && (decpt < digs || decpt - digs < DBL_DIG+1)) { + int i = 0, j = 0, n; + if (decpt > 0) { + memcpy(buf + j, p + i, (n = decpt > digs ? digs : decpt)); + i += n, j += n; + if ((n = decpt - n) > 0) { + memset(buf + j, '0', n); + j += n; } - memcpy(ptr, ".0", 2); } else { - goto exp; + buf[j++] = '0'; } - } - else if (decpt > -4) { - long len; - char *ptr; - rb_str_cat(s, "0.", 2); - rb_str_resize(s, (len = RSTRING_LEN(s)) - decpt + digs); - ptr = RSTRING_PTR(s); - memset(ptr += len, '0', -decpt); - memcpy(ptr -= decpt, buf, digs); + buf[j++] = '.'; + if (decpt < 0) { + memset(buf + j, '0', -decpt); + j -= decpt, decpt = 0; + } + if (decpt < digs) { + memcpy(buf + j, p + i, (n = digs - decpt)); + j += n; + } + else { + buf[j++] = '0'; + } + digs = j; } else { - exp: + buf[0] = p[0]; + buf[1] = '.'; if (digs > 1) { - memmove(buf + 2, buf + 1, digs - 1); + memcpy(buf + 2, p + 1, digs++ - 1); } else { buf[2] = '0'; - digs++; + digs = 3; } - buf[1] = '.'; - rb_str_cat(s, buf, digs + 1); - rb_str_catf(s, "e%+03d", decpt - 1); + digs += snprintf(buf + digs, size - digs, "e%+03d", decpt - 1); } - return s; + xfree(p); + return digs + sign; } /* |