Oops! Spoke too soon.

There is a new big-endian bug:

   - *Quad_RVAL.tc:* DOMAIN ERROR in 2⍟ on random 32-bit floats.
   - *Domino_stress.tc:* DOMAIN ERROR in A⌹B on random matrices.

*Cause:* Quad_RVAL::random_ieee() builds a random double by writing the
bytes of a double/char[8] union, assuming little-endian layout. On sparc64
the exponent lands in the wrong bytes. Asking for 6 random floats there
gives
5.29E45 ¯1 ¯9.5E212 65329.9 ¯9.6E165 ¯2.7E143; amd64 gives values in [0,1).

*Fix:* a small patch, below. It assembles the bits in a uint64_t and
memcpy()s them into the double. It takes the same bits of the random number
as before, so the random sequence is unchanged on amd64; I checked that
with a fixed seed. On amd64 it builds and both testcases pass.
There is also a failure due to a bug in a test which hard-codes Linux
socket constants (SOL_SOCKET=1, SO_REUSEADDR=2) which fails on sparc64.
I'll patch that too when I get a chance.
--- a/trunk/src/Quad_RVAL.cc
+++ b/trunk/src/Quad_RVAL.cc
@@ -22,6 +22,7 @@
 */
 
 #include <stdlib.h>
+#include <string.h>
 
 #include "Avec.hh"
 #include "Common.hh"
@@ -736,38 +737,34 @@
 double
 Quad_RVAL::random_ieee()
 {
-union { double f;
-        char bytes[8];
-      } u;
+double f;
    do {
         const int64_t rand64 = rand17()
                              ^ (rand17() << 16)
                              ^ (rand17() << 32)
                              ^ (rand17() << 48);
-        
+
         enum { BIAS     = 1023,          // IEEE
                EXPO     = 0 + BIAS,      // 2^0
-               EXPO_LSB = EXPO & 0x0F,   // 0..15
-               EXPO_MSB = EXPO >> 4      // 0..15
              };
 
-        u.bytes[7] = EXPO_MSB;                // SIGN + and exponent MSBs
-        u.bytes[6] = (EXPO_LSB << 4)          // exponent LSBs
-                   | (rand64 >> 56 & 0x0F);   // 52 bit fraction MSBs
-        u.bytes[5] = rand64 >> 40;            // 52 bit fraction
-        u.bytes[4] = rand64 >> 32;            // 52 bit fraction
-        u.bytes[3] = rand64 >> 24;            // 52 bit fraction
-        u.bytes[2] = rand64 >> 16;            // 52 bit fraction
-        u.bytes[1] = rand64 >>  8;            // 52 bit fraction
-        u.bytes[0] = rand64 >>  0;            // 52 bit fraction LSBs
-      } while (!isnormal(u.f));
+        // sign +, exponent EXPO, and a random 52 bit fraction (bits 0-47 and
+        // 56-59 of rand64). Assemble the bits in a uint64_t and memcpy() them
+        // into f, rather than storing bytes into a union, so that the result
+        // does not depend on the host byte order.
+        //
+        const uint64_t bits = uint64_t(EXPO) << 52
+                            | (uint64_t(rand64) >> 56 & 0x0F) << 48
+                            | (uint64_t(rand64) & 0xFFFFFFFFFFFFULL);
+        memcpy(&f, &bits, sizeof(f));
+      } while (!isnormal(f));
 
-   // at this point: 1.0 < u.f < 2.0
+   // at this point: 1.0 < f < 2.0
    //
    if (desired_purpose == 1)   // APL2 mode: an IEEE 32-bit (float) value
-      return double(float(u.f - 1.0));
+      return double(float(f - 1.0));
 
-   return u.f - 1.0;
+   return f - 1.0;
 }
 //────────────────────────────────────────────────────────────────────────────
 void
  • [PATCH] big-en... Barak A. Pearlmutter
    • Re: [PATC... Dr . Jürgen Sauermann via Bugs and suggestions for GNU APL
      • Re: [... Barak A. Pearlmutter
      • Re: [... Barak A. Pearlmutter
        • R... Dr . Jürgen Sauermann via Bugs and suggestions for GNU APL
        • R... Barak A. Pearlmutter
          • ... Dr . Jürgen Sauermann via Bugs and suggestions for GNU APL
        • R... Barak A. Pearlmutter

Reply via email to