diff --git a/ChangeLog b/ChangeLog index 9fadd570a2..1623eb4b1e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Thu May 13 13:30:05 2010 Nobuyoshi Nakada + + * marshal.c (w_float): use minimal representation. + + * numeric.c (ruby_dbl2cstr): split from rb_float_new. + Thu May 13 13:09:24 2010 Nobuyoshi Nakada * vm_core.h (rb_vm_get_sourceline): moved from eval_intern.h for diff --git a/marshal.c b/marshal.c index 702dd66357..857dd7361c 100644 --- a/marshal.c +++ b/marshal.c @@ -245,6 +245,8 @@ w_bytes(const char *s, long n, struct dump_arg *arg) w_nbyte(s, n, arg); } +#define w_cstr(s, arg) w_bytes(s, strlen(s), arg) + static void w_short(int x, struct dump_arg *arg) { @@ -308,35 +310,6 @@ w_long(long x, struct dump_arg *arg) #define MANT_BITS 8 #endif -static int -save_mantissa(double d, char *buf) -{ - int e, i = 0; - unsigned long m; - double n; - - d = modf(ldexp(frexp(fabs(d), &e), DECIMAL_MANT), &d); - if (d > 0) { - buf[i++] = 0; - do { - d = modf(ldexp(d, MANT_BITS), &n); - m = (unsigned long)n; -#if MANT_BITS > 24 - buf[i++] = (char)(m >> 24); -#endif -#if MANT_BITS > 16 - buf[i++] = (char)(m >> 16); -#endif -#if MANT_BITS > 8 - buf[i++] = (char)(m >> 8); -#endif - buf[i++] = (char)m; - } while (d > 0); - while (!buf[i - 1]) --i; - } - return i; -} - static double load_mantissa(double d, const char *buf, long len) { @@ -370,7 +343,6 @@ load_mantissa(double d, const char *buf, long len) } #else #define load_mantissa(d, buf, len) (d) -#define save_mantissa(d, buf) 0 #endif #ifdef DBL_DIG @@ -382,29 +354,23 @@ load_mantissa(double d, const char *buf, long len) static void w_float(double d, struct dump_arg *arg) { + int ruby_dbl2cstr(double value, char *buf, int size); char buf[FLOAT_DIG + (DECIMAL_MANT + 7) / 8 + 10]; if (isinf(d)) { - if (d < 0) strcpy(buf, "-inf"); - else strcpy(buf, "inf"); + if (d < 0) w_cstr("-inf", arg); + else w_cstr("inf", arg); } else if (isnan(d)) { - strcpy(buf, "nan"); + w_cstr("nan", arg); } else if (d == 0.0) { - if (1.0/d < 0) strcpy(buf, "-0"); - else strcpy(buf, "0"); + if (1.0/d < 0) w_cstr("-0", arg); + else w_cstr("0", arg); } else { - size_t len; - - /* xxx: should not use system's sprintf(3) */ - snprintf(buf, sizeof(buf), "%.*g", FLOAT_DIG, d); - len = strlen(buf); - w_bytes(buf, len + save_mantissa(d, buf + len), arg); - return; + w_bytes(buf, ruby_dbl2cstr(d, buf, (int)sizeof(buf)), arg); } - w_bytes(buf, strlen(buf), arg); } static void diff --git a/numeric.c b/numeric.c index 00d670b70f..31b3756d25 100644 --- a/numeric.c +++ b/numeric.c @@ -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; } /*