From aede0cf378b29b13b701ba23d45a123bda00c7a2 Mon Sep 17 00:00:00 2001 From: nobu Date: Tue, 22 Apr 2003 10:08:57 +0000 Subject: * marshal.c (save_mantissa, load_mantissa): for interoperability should count cut-down bit from topmost. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3713 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- marshal.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 17 deletions(-) (limited to 'marshal.c') diff --git a/marshal.c b/marshal.c index 68a516495f..95712c870d 100644 --- a/marshal.c +++ b/marshal.c @@ -185,18 +185,47 @@ w_long(x, arg) } #ifdef DBL_MANT_DIG +#define DECIMAL_MANT (53-16) /* from IEEE754 double precision */ + +#if DBL_MANT_DIG > 32 +#define MANT_BITS 32 +#elif DBL_MANT_DIG > 24 +#define MANT_BITS 24 +#elif DBL_MANT_DIG > 16 +#define MANT_BITS 16 +#else +#define MANT_BITS 8 +#endif + static int save_mantissa(d, buf) double d; char *buf; { - int e, m; - - m = (int)(modf(ldexp(frexp(fabs(d), &e), DBL_MANT_DIG - 16), &d) * 0x10000); - *buf++ = 0; - *buf++ = m >> 8; - *buf++ = m; - return 3; + 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++] = m >> 24; +#endif +#if MANT_BITS > 16 + buf[i++] = m >> 16; +#endif +#if MANT_BITS > 8 + buf[i++] = m >> 8; +#endif + buf[i++] = m; + } while (d > 0); + while (!buf[i - 1]) --i; + } + return i; } static double @@ -205,13 +234,29 @@ load_mantissa(d, buf, len) const char *buf; int len; { - if (len > 0) { - int e, s = d < 0, dig = len << 3; - unsigned long m = 0; - - modf(ldexp(frexp(fabs(d), &e), DBL_MANT_DIG - dig), &d); - do {m = (m << 8) | (*buf++ & 0xff);} while (--len); - d = ldexp(frexp(d + ldexp((double)m, -dig), &dig), e); + if (--len > 0 && !*buf++) { /* binary mantissa mark */ + int e, s = d < 0, dig = 0; + unsigned long m; + + modf(ldexp(frexp(fabs(d), &e), DECIMAL_MANT), &d); + do { + m = 0; + switch (len) { + default: m = *buf++ & 0xff; +#if MANT_BITS > 24 + case 3: m = (m << 8) | (*buf++ & 0xff); +#endif +#if MANT_BITS > 16 + case 2: m = (m << 8) | (*buf++ & 0xff); +#endif +#if MANT_BITS > 8 + case 1: m = (m << 8) | (*buf++ & 0xff); +#endif + } + dig -= len < MANT_BITS / 8 ? 8 * (unsigned)len : MANT_BITS; + d += ldexp((double)m, dig); + } while ((len -= MANT_BITS / 8) > 0); + d = ldexp(d, e - DECIMAL_MANT); if (s) d = -d; } return d; @@ -983,9 +1028,7 @@ r_object0(arg, proc) else { char *e; d = strtod(ptr, &e); - if (!*e++) { - d = load_mantissa(d, e, RSTRING(str)->len - (e - ptr)); - } + d = load_mantissa(d, e, RSTRING(str)->len - (e - ptr)); } v = rb_float_new(d); r_regist(v, arg); -- cgit v1.2.3