Hi Matz and Nobu again,

This is a tricky problem.  I have rewritten my patch in a way that I hope
is endian-independent, and furthermore allows you to load and save exactly
across any IEEE754 system, whether big or little endian floats.
Unfortunately,  I could find only one bigendian system to test on, and
when my friend tried to compile ruby on it, it failed, so I was
unable to complete the testing on this new version of the patch.
(against the current version in the CVS tree)  Maybe there is some kind
soul out there that would like to help?  I also took Matz suggestion and
followed Nobu's example of how to properly put the special two bytes at
the end of the string after the nul for backwards compatibility.  All I
can say with confidence is that this patch also passes all my tests on the
x86 linux machines at my disposal.  Cheers,

Rudi

P.S.  I am embarrassed to use some extra globals to make this patch work.

--- marshal.c	2003-04-19 12:48:14.000000000 +0200
+++ marshal.c	2003-04-19 12:42:48.000000000 +0200
@@ -182,4 +182,72 @@ w_long(x, arg)
 }
 
+#define FT_OTHER 0
+#define FT_IEEE754 1
+#define FT_UNDEFINED 5
+
+static int floatingType = FT_UNDEFINED;
+static int floatingStart, floatingDir;  /* forgive me */
+
+static void checkFloatingType()
+{
+  if (floatingType == FT_UNDEFINED) {
+    volatile double t = 1.234;
+    volatile unsigned char *b = (unsigned char *) &t;
+    if (b[0] == 0x58 && b[1] == 0x39 && b[2] == 0xb4 && b[3] == 0xc8 &&
+        b[4] == 0x76 && b[5] == 0xbe && b[6] == 0xf3 && b[7] == 0x3f) {
+      floatingType = FT_IEEE754;
+      floatingStart = 0;
+      floatingDir = 1;
+    }
+    if (b[7] == 0x58 && b[6] == 0x39 && b[5] == 0xb4 && b[4] == 0xc8 &&
+        b[3] == 0x76 && b[2] == 0xbe && b[1] == 0xf3 && b[0] == 0x3f) {
+      floatingType = FT_IEEE754;
+      floatingStart = 7;
+      floatingDir = -1;
+    }
+    if (floatingType == FT_UNDEFINED)
+        floatingType = FT_OTHER;
+  }
+  return;
+}
+
+#define GETBYTE(d, x) ((unsigned char *) &d)[floatingStart + floatingDir * x]
+
+static double fixMantissaBits(double d, unsigned char *buf)
+{
+  int encodedType = buf[1] >> 6;
+  checkFloatingType();
+  if (floatingType != encodedType)
+    return d;
+  switch(floatingType) {
+    case FT_IEEE754:
+      GETBYTE(d,0) = buf[0];
+      GETBYTE(d,1) &= 0xc0;
+      GETBYTE(d,1) |= buf[1] & ~0xc0;
+      break;
+    default:
+      break; 
+  }
+  return d;
+}
+
+static double saveMantissaBits(double d, unsigned char *buf)
+{
+  unsigned char result;
+  checkFloatingType();
+  switch (floatingType) {
+    case FT_IEEE754:
+      buf[0] = GETBYTE(d, 0);
+      buf[1] = GETBYTE(d, 1);
+      break;
+    default:
+      buf[0] = 1;
+      buf[1] = 1;
+      break;
+  }
+  buf[1] = (buf[1] &  ~0xc0) | (floatingType << 6);
+}
+
+
 static void
 w_float(d, arg)
@@ -202,7 +270,8 @@ w_float(d, arg)
     else {
 	/* xxx: should not use system's sprintf(3) */
-	sprintf(buf, "%.16g", d);
+	sprintf(buf, "%.17g", d);
+  saveMantissaBits(d, buf+strlen(buf)+1);
     }
-    w_bytes(buf, strlen(buf), arg);
+    w_bytes(buf, strlen(buf)+3, arg);
 }
 
@@ -931,4 +1000,5 @@ r_object0(arg, proc)
 	    else {
 		d = strtod(RSTRING(str)->ptr, 0);
+    d = fixMantissaBits(d, RSTRING(str)->ptr + strlen(RSTRING(str)->ptr) + 1);
 	    }
 	    v = rb_float_new(d);