--- lib/erl_interface/src/misc/putget.h.orig 2008-07-10 11:50:30.068128000 -0400 +++ lib/erl_interface/src/misc/putget.h 2008-07-10 17:42:02.273245000 -0400 @@ -51,6 +51,18 @@ (s) += 4; \ } while (0) +#define put64be(s,n) do { \ + (s)[0] = ((n) >> 56) & 0xff; \ + (s)[1] = ((n) >> 48) & 0xff; \ + (s)[2] = ((n) >> 40) & 0xff; \ + (s)[3] = ((n) >> 32) & 0xff; \ + (s)[4] = ((n) >> 24) & 0xff; \ + (s)[5] = ((n) >> 16) & 0xff; \ + (s)[6] = ((n) >> 8) & 0xff; \ + (s)[7] = (n) & 0xff; \ + (s) += 8; \ +} while (0) + #define get8(s) \ ((s) += 1, \ ((unsigned char *)(s))[-1] & 0xff) @@ -79,4 +91,15 @@ (((unsigned char *)(s))[-2] << 8) | \ ((unsigned char *)(s))[-1])) +#define get64be(s) \ + ((s) += 8, \ + (((unsigned long long)((unsigned char *)(s))[-8] << 56) | \ + ((unsigned long long)((unsigned char *)(s))[-7] << 48) | \ + ((unsigned long long)((unsigned char *)(s))[-6] << 40) | \ + ((unsigned long long)((unsigned char *)(s))[-5] << 32) | \ + ((unsigned long long)((unsigned char *)(s))[-4] << 24) | \ + ((unsigned long long)((unsigned char *)(s))[-3] << 16) | \ + ((unsigned long long)((unsigned char *)(s))[-2] << 8) | \ + (unsigned long long)((unsigned char *)(s))[-1])) + #endif /* _PUTGET_H */ --- lib/erl_interface/src/decode/decode_double.c.orig 2008-07-10 10:47:18.488729000 -0400 +++ lib/erl_interface/src/decode/decode_double.c 2008-07-10 15:52:07.087747000 -0400 @@ -20,18 +20,51 @@ #include "eiext.h" #include "putget.h" - int ei_decode_double(const char *buf, int *index, double *p) { const char *s = buf + *index; const char *s0 = s; double f; - if (get8(s) != ERL_FLOAT_EXT) return -1; - + switch (get8(s)) { + case ERL_FLOAT_EXT: if (sscanf(s, "%lf", &f) != 1) return -1; - s += 31; + break; + case NEW_FLOAT_EXT: { + // IEEE 754 decoder + const unsigned int bits = 64; + const unsigned int expbits = 11; + const unsigned int significantbits = bits - expbits - 1; // -1 for sign bit + unsigned long long i = get64be(s); + long long shift; + unsigned bias; + + if (!p) + break; + else if (i == 0) + f = 0.0; + else { + // get the significant + f = (i & ((1LL << significantbits)-1)); // mask + f /= (1LL << significantbits); // convert back to float + f += 1.0f; // add the one back on + + // get the exponent + bias = (1 << (expbits-1)) - 1; + shift = ((i >> significantbits) & ((1LL << expbits)-1)) - bias; + while (shift > 0) { f *= 2.0; shift--; } + while (shift < 0) { f /= 2.0; shift++; } + + // signness + f *= (i >> (bits-1)) & 1 ? -1.0: 1.0; + } + break; + } + default: + return -1; + } + if (p) *p = f; *index += s-s0; return 0; --- lib/erl_interface/src/encode/encode_double.c.orig 2008-07-10 12:12:57.591860000 -0400 +++ lib/erl_interface/src/encode/encode_double.c 2008-07-10 16:08:31.248148000 -0400 @@ -26,16 +26,56 @@ char *s = buf + *index; char *s0 = s; - if (!buf) s ++; - else { + #ifdef USE_OLD_FLOAT_ENCODER + const int old_format = 1; + #else + const int old_format = 0; + #endif + + if (!buf) + s = old_format ? s+32 : s+9; + else if (old_format) { put8(s,ERL_FLOAT_EXT); memset(s, 0, 31); sprintf(s, "%.20e", p); - } s += 31; + } else { /* use IEEE 754 format */ + const unsigned int bits = 64; + const unsigned int expbits = 11; + const unsigned int significantbits = bits - expbits - 1; // -1 for sign bit + long long sign, exp, significant; + long double norm; + int shift; - *index += s-s0; + put8(s, NEW_FLOAT_EXT); + memset(s, 0, 8); + + if (p == 0.0) + s += 8; + else { + // check sign and begin normalization + if (p < 0) { sign = 1; norm = -p; } + else { sign = 0; norm = p; } + + // get the normalized form of p and track the exponent + shift = 0; + while(norm >= 2.0) { norm /= 2.0; shift++; } + while(norm < 1.0) { norm *= 2.0; shift--; } + norm = norm - 1.0; + // calculate the binary form (non-float) of the significant data + significant = (long long) ( norm * ((1LL << significantbits) + 0.5f) ); + + // get the biased exponent + exp = shift + ((1 << (expbits-1)) - 1); // shift + bias + + // get the final answer + exp = (sign << (bits-1)) | (exp << (bits-expbits-1)) | significant; + put64be(s, exp); + } + } + + *index += s-s0; return 0; } --- lib/erl_interface/include/ei.h.orig 2008-07-10 10:46:09.056225000 -0400 +++ lib/erl_interface/include/ei.h 2008-07-10 16:06:12.780756000 -0400 @@ -109,6 +109,7 @@ #define ERL_SMALL_INTEGER_EXT 'a' #define ERL_INTEGER_EXT 'b' #define ERL_FLOAT_EXT 'c' +#define NEW_FLOAT_EXT 'F' #define ERL_ATOM_EXT 'd' #define ERL_REFERENCE_EXT 'e' #define ERL_NEW_REFERENCE_EXT 'r'