summaryrefslogtreecommitdiff
path: root/marshal.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-04-22 10:08:57 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-04-22 10:08:57 +0000
commitaede0cf378b29b13b701ba23d45a123bda00c7a2 (patch)
tree3ff2135df5beb53de375432ce6135eb2c0afe1c2 /marshal.c
parentb4945ec14135e6b1280ca93f2371e346351850ce (diff)
* 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
Diffstat (limited to 'marshal.c')
-rw-r--r--marshal.c77
1 files changed, 60 insertions, 17 deletions
diff --git a/marshal.c b/marshal.c
index 68a5164..95712c8 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);