Index: Include/floatobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/floatobject.h,v retrieving revision 2.22 diff -c -r2.22 floatobject.h *** Include/floatobject.h 20 Mar 2003 20:53:29 -0000 2.22 --- Include/floatobject.h 14 Apr 2005 07:42:43 -0000 *************** *** 55,67 **** * routines produce a C double from such a string. The suffix (4 or 8) * specifies the number of bytes in the string. * ! * Excepting NaNs and infinities (which aren't handled correctly), the 4- ! * byte format is identical to the IEEE-754 single precision format, and ! * the 8-byte format to the IEEE-754 double precision format. On non- ! * IEEE platforms with more precision, or larger dynamic range, than ! * 754 supports, not all values can be packed; on non-IEEE platforms with ! * less precision, or smaller dynamic range, not all values can be ! * unpacked. What happens in such cases is partly accidental (alas). */ /* The pack routines write 4 or 8 bytes, starting at p. le is a bool --- 55,72 ---- * routines produce a C double from such a string. The suffix (4 or 8) * specifies the number of bytes in the string. * ! * On platforms that appear to use (see _PyFloat_Init()) IEEE-754 formats ! * these functions work by copying bits. On other platforms, the formats the ! * 4- byte format is identical to the IEEE-754 single precision format, and ! * the 8-byte format to the IEEE-754 double precision format, although the ! * packing of INFs and NaNs (if such things exist on the platform) isn't ! * handled correctly, and attempting to unpack a string containing an IEEE ! * INF or NaN will raise an exception. ! * ! * On non-IEEE platforms with more precision, or larger dynamic range, than ! * 754 supports, not all values can be packed; on non-IEEE platforms with less ! * precision, or smaller dynamic range, not all values can be unpacked. What ! * happens in such cases is partly accidental (alas). */ /* The pack routines write 4 or 8 bytes, starting at p. le is a bool *************** *** 70,77 **** * first, at p). * Return value: 0 if all is OK, -1 if error (and an exception is * set, most likely OverflowError). ! * Bug: What this does is undefined if x is a NaN or infinity. ! * Bug: -0.0 and +0.0 produce the same string. */ PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le); PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le); --- 75,83 ---- * first, at p). * Return value: 0 if all is OK, -1 if error (and an exception is * set, most likely OverflowError). ! * There are two problems on non-IEEE platforms: ! * 1): What this does is undefined if x is a NaN or infinity. ! * 2): -0.0 and +0.0 produce the same string. */ PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le); PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le); *************** *** 81,89 **** * last, at p+3 or p+7), false if big-endian (exponent first, at p). * Return value: The unpacked double. On error, this is -1.0 and * PyErr_Occurred() is true (and an exception is set, most likely ! * OverflowError). ! * Bug: What this does is undefined if the string represents a NaN or ! * infinity. */ PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le); PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); --- 87,94 ---- * last, at p+3 or p+7), false if big-endian (exponent first, at p). * Return value: The unpacked double. On error, this is -1.0 and * PyErr_Occurred() is true (and an exception is set, most likely ! * OverflowError). Note that on a non-IEEE platform this will refuse ! * to unpack a string that represents a NaN or infinity. */ PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le); PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); Index: Include/pythonrun.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/pythonrun.h,v retrieving revision 2.65 diff -c -r2.65 pythonrun.h *** Include/pythonrun.h 7 Oct 2004 03:58:06 -0000 2.65 --- Include/pythonrun.h 14 Apr 2005 07:42:45 -0000 *************** *** 105,110 **** --- 105,111 ---- PyAPI_FUNC(void) _PyImportHooks_Init(void); PyAPI_FUNC(int) _PyFrame_Init(void); PyAPI_FUNC(int) _PyInt_Init(void); + PyAPI_FUNC(void) _PyFloat_Init(void); /* Various internal finalizers */ PyAPI_FUNC(void) _PyExc_Fini(void); Index: Objects/floatobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/floatobject.c,v retrieving revision 2.134 diff -c -r2.134 floatobject.c *** Objects/floatobject.c 23 Sep 2004 19:22:41 -0000 2.134 --- Objects/floatobject.c 14 Apr 2005 07:42:57 -0000 *************** *** 1075,1080 **** --- 1075,1135 ---- float_new, /* tp_new */ }; + /* this is for the benefit of the pack/unpack routines below */ + + typedef enum { + unknown_format, ieee_big_endian_format, ieee_little_endian_format + } float_format_type; + + static float_format_type double_format, float_format; + + void + _PyFloat_Init(void) + { + /* We attempt to determine if this machine is using IEEE + floating point formats by peering at the bits of some + carefully chosen values. If it looks like we are on an + IEEE platform, the float packing/unpacking routines can + just copy bits, if not they resort to arithmetic & shifts + and masks. The shifts & masks approach works on all finite + values, but what happens to infinities, NaNs and signed + zeroes on packing is an accident, and attempting to unpack + a NaN or an infinity will raise an exception. + + Note that if we're on some whacked-out platform which uses + IEEE formats but isn't strictly little-endian or big- + endian, we will fall back to the portable shifts & masks + method. */ + + #if SIZEOF_DOUBLE == 8 + { + double x = 9006104071832581.0; + if (memcmp(&x, "\x43\x3f\xff\x01\x02\x03\x04\x05", 8) == 0) + double_format = ieee_big_endian_format; + else if (memcmp(&x, "\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0) + double_format = ieee_little_endian_format; + else + double_format = unknown_format; + } + #else + double_format = unknown_format; + #endif + + #if SIZEOF_FLOAT == 4 + { + float y = 16711938.0; + if (memcmp(&y, "\x4b\x7f\x01\x02", 4) == 0) + float_format = ieee_big_endian_format; + else if (memcmp(&y, "\x02\x01\x7f\x4b", 4) == 0) + float_format = ieee_little_endian_format; + else + float_format = unknown_format; + } + #else + float_format = unknown_format; + #endif + } + void PyFloat_Fini(void) { *************** *** 1162,1467 **** int _PyFloat_Pack4(double x, unsigned char *p, int le) { ! unsigned char sign; ! int e; ! double f; ! unsigned int fbits; ! int incr = 1; ! if (le) { ! p += 3; ! incr = -1; ! } ! if (x < 0) { ! sign = 1; ! x = -x; ! } ! else ! sign = 0; ! f = frexp(x, &e); ! /* Normalize f to be in the range [1.0, 2.0) */ ! if (0.5 <= f && f < 1.0) { ! f *= 2.0; ! e--; ! } ! else if (f == 0.0) ! e = 0; ! else { ! PyErr_SetString(PyExc_SystemError, ! "frexp() result out of range"); return -1; } ! ! if (e >= 128) ! goto Overflow; ! else if (e < -126) { ! /* Gradual underflow */ ! f = ldexp(f, 126 + e); ! e = 0; ! } ! else if (!(e == 0 && f == 0.0)) { ! e += 127; ! f -= 1.0; /* Get rid of leading 1 */ ! } ! ! f *= 8388608.0; /* 2**23 */ ! fbits = (unsigned int)(f + 0.5); /* Round */ ! assert(fbits <= 8388608); ! if (fbits >> 23) { ! /* The carry propagated out of a string of 23 1 bits. */ ! fbits = 0; ! ++e; ! if (e >= 255) ! goto Overflow; } - - /* First byte */ - *p = (sign << 7) | (e >> 1); - p += incr; - - /* Second byte */ - *p = (char) (((e & 1) << 7) | (fbits >> 16)); - p += incr; - - /* Third byte */ - *p = (fbits >> 8) & 0xFF; - p += incr; - - /* Fourth byte */ - *p = fbits & 0xFF; - - /* Done */ - return 0; - - Overflow: - PyErr_SetString(PyExc_OverflowError, - "float too large to pack with f format"); - return -1; } int _PyFloat_Pack8(double x, unsigned char *p, int le) { ! unsigned char sign; ! int e; ! double f; ! unsigned int fhi, flo; ! int incr = 1; ! if (le) { ! p += 7; ! incr = -1; ! } ! if (x < 0) { ! sign = 1; ! x = -x; ! } ! else ! sign = 0; ! f = frexp(x, &e); ! /* Normalize f to be in the range [1.0, 2.0) */ ! if (0.5 <= f && f < 1.0) { ! f *= 2.0; ! e--; ! } ! else if (f == 0.0) ! e = 0; ! else { ! PyErr_SetString(PyExc_SystemError, ! "frexp() result out of range"); return -1; } ! if (e >= 1024) ! goto Overflow; ! else if (e < -1022) { ! /* Gradual underflow */ ! f = ldexp(f, 1022 + e); ! e = 0; ! } ! else if (!(e == 0 && f == 0.0)) { ! e += 1023; ! f -= 1.0; /* Get rid of leading 1 */ ! } ! ! /* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */ ! f *= 268435456.0; /* 2**28 */ ! fhi = (unsigned int)f; /* Truncate */ ! assert(fhi < 268435456); ! ! f -= (double)fhi; ! f *= 16777216.0; /* 2**24 */ ! flo = (unsigned int)(f + 0.5); /* Round */ ! assert(flo <= 16777216); ! if (flo >> 24) { ! /* The carry propagated out of a string of 24 1 bits. */ ! flo = 0; ! ++fhi; ! if (fhi >> 28) { ! /* And it also progagated out of the next 28 bits. */ ! fhi = 0; ! ++e; ! if (e >= 2047) ! goto Overflow; } } - - /* First byte */ - *p = (sign << 7) | (e >> 4); - p += incr; - - /* Second byte */ - *p = (unsigned char) (((e & 0xF) << 4) | (fhi >> 24)); - p += incr; - - /* Third byte */ - *p = (fhi >> 16) & 0xFF; - p += incr; - - /* Fourth byte */ - *p = (fhi >> 8) & 0xFF; - p += incr; - - /* Fifth byte */ - *p = fhi & 0xFF; - p += incr; - - /* Sixth byte */ - *p = (flo >> 16) & 0xFF; - p += incr; - - /* Seventh byte */ - *p = (flo >> 8) & 0xFF; - p += incr; - - /* Eighth byte */ - *p = flo & 0xFF; - p += incr; - - /* Done */ - return 0; - - Overflow: - PyErr_SetString(PyExc_OverflowError, - "float too large to pack with d format"); - return -1; } double _PyFloat_Unpack4(const unsigned char *p, int le) { ! unsigned char sign; ! int e; ! unsigned int f; ! double x; ! int incr = 1; ! ! if (le) { ! p += 3; ! incr = -1; ! } ! ! /* First byte */ ! sign = (*p >> 7) & 1; ! e = (*p & 0x7F) << 1; ! p += incr; ! ! /* Second byte */ ! e |= (*p >> 7) & 1; ! f = (*p & 0x7F) << 16; ! p += incr; ! ! /* Third byte */ ! f |= *p << 8; ! p += incr; ! ! /* Fourth byte */ ! f |= *p; ! ! x = (double)f / 8388608.0; ! ! /* XXX This sadly ignores Inf/NaN issues */ ! if (e == 0) ! e = -126; ! else { ! x += 1.0; ! e -= 127; ! } ! x = ldexp(x, e); ! if (sign) ! x = -x; ! return x; } double _PyFloat_Unpack8(const unsigned char *p, int le) { ! unsigned char sign; ! int e; ! unsigned int fhi, flo; ! double x; ! int incr = 1; ! ! if (le) { ! p += 7; ! incr = -1; ! } ! ! /* First byte */ ! sign = (*p >> 7) & 1; ! e = (*p & 0x7F) << 4; ! p += incr; ! ! /* Second byte */ ! e |= (*p >> 4) & 0xF; ! fhi = (*p & 0xF) << 24; ! p += incr; ! ! /* Third byte */ ! fhi |= *p << 16; ! p += incr; ! ! /* Fourth byte */ ! fhi |= *p << 8; ! p += incr; ! ! /* Fifth byte */ ! fhi |= *p; ! p += incr; ! ! /* Sixth byte */ ! flo = *p << 16; ! p += incr; ! ! /* Seventh byte */ ! flo |= *p << 8; ! p += incr; ! ! /* Eighth byte */ ! flo |= *p; ! ! x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */ ! x /= 268435456.0; /* 2**28 */ ! ! /* XXX This sadly ignores Inf/NaN */ ! if (e == 0) ! e = -1022; ! else { ! x += 1.0; ! e -= 1023; ! } ! x = ldexp(x, e); ! if (sign) ! x = -x; ! return x; } --- 1217,1609 ---- int _PyFloat_Pack4(double x, unsigned char *p, int le) { ! if (float_format == unknown_format) { ! unsigned char sign; ! int e; ! double f; ! unsigned int fbits; ! int incr = 1; ! ! if (le) { ! p += 3; ! incr = -1; ! } ! if (x < 0) { ! sign = 1; ! x = -x; ! } ! else ! sign = 0; ! f = frexp(x, &e); ! /* Normalize f to be in the range [1.0, 2.0) */ ! if (0.5 <= f && f < 1.0) { ! f *= 2.0; ! e--; ! } ! else if (f == 0.0) ! e = 0; ! else { ! PyErr_SetString(PyExc_SystemError, ! "frexp() result out of range"); ! return -1; ! } ! if (e >= 128) ! goto Overflow; ! else if (e < -126) { ! /* Gradual underflow */ ! f = ldexp(f, 126 + e); ! e = 0; ! } ! else if (!(e == 0 && f == 0.0)) { ! e += 127; ! f -= 1.0; /* Get rid of leading 1 */ ! } ! ! f *= 8388608.0; /* 2**23 */ ! fbits = (unsigned int)(f + 0.5); /* Round */ ! assert(fbits <= 8388608); ! if (fbits >> 23) { ! /* The carry propagated out of a string of 23 1 bits. */ ! fbits = 0; ! ++e; ! if (e >= 255) ! goto Overflow; ! } ! ! /* First byte */ ! *p = (sign << 7) | (e >> 1); ! p += incr; ! ! /* Second byte */ ! *p = (char) (((e & 1) << 7) | (fbits >> 16)); ! p += incr; ! ! /* Third byte */ ! *p = (fbits >> 8) & 0xFF; ! p += incr; ! ! /* Fourth byte */ ! *p = fbits & 0xFF; ! ! /* Done */ ! return 0; ! ! Overflow: ! PyErr_SetString(PyExc_OverflowError, ! "float too large to pack with f format"); return -1; } ! else { ! float y = x; ! const char *s = (char*)&y; ! int i, incr = 1; ! ! if ((float_format == ieee_little_endian_format && !le) ! || (float_format == ieee_big_endian_format && le)) { ! p += 3; ! incr = -1; ! } ! ! for (i = 0; i < 4; i++) { ! *p = *s++; ! p += incr; ! } ! return 0; } } int _PyFloat_Pack8(double x, unsigned char *p, int le) { ! if (double_format == unknown_format) { ! unsigned char sign; ! int e; ! double f; ! unsigned int fhi, flo; ! int incr = 1; ! ! if (le) { ! p += 7; ! incr = -1; ! } ! if (x < 0) { ! sign = 1; ! x = -x; ! } ! else ! sign = 0; ! f = frexp(x, &e); ! /* Normalize f to be in the range [1.0, 2.0) */ ! if (0.5 <= f && f < 1.0) { ! f *= 2.0; ! e--; ! } ! else if (f == 0.0) ! e = 0; ! else { ! PyErr_SetString(PyExc_SystemError, ! "frexp() result out of range"); ! return -1; ! } ! if (e >= 1024) ! goto Overflow; ! else if (e < -1022) { ! /* Gradual underflow */ ! f = ldexp(f, 1022 + e); ! e = 0; ! } ! else if (!(e == 0 && f == 0.0)) { ! e += 1023; ! f -= 1.0; /* Get rid of leading 1 */ ! } ! ! /* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */ ! f *= 268435456.0; /* 2**28 */ ! fhi = (unsigned int)f; /* Truncate */ ! assert(fhi < 268435456); ! ! f -= (double)fhi; ! f *= 16777216.0; /* 2**24 */ ! flo = (unsigned int)(f + 0.5); /* Round */ ! assert(flo <= 16777216); ! if (flo >> 24) { ! /* The carry propagated out of a string of 24 1 bits. */ ! flo = 0; ! ++fhi; ! if (fhi >> 28) { ! /* And it also progagated out of the next 28 bits. */ ! fhi = 0; ! ++e; ! if (e >= 2047) ! goto Overflow; ! } ! } ! ! /* First byte */ ! *p = (sign << 7) | (e >> 4); ! p += incr; ! ! /* Second byte */ ! *p = (unsigned char) (((e & 0xF) << 4) | (fhi >> 24)); ! p += incr; ! ! /* Third byte */ ! *p = (fhi >> 16) & 0xFF; ! p += incr; ! ! /* Fourth byte */ ! *p = (fhi >> 8) & 0xFF; ! p += incr; ! ! /* Fifth byte */ ! *p = fhi & 0xFF; ! p += incr; ! ! /* Sixth byte */ ! *p = (flo >> 16) & 0xFF; ! p += incr; ! ! /* Seventh byte */ ! *p = (flo >> 8) & 0xFF; ! p += incr; ! ! /* Eighth byte */ ! *p = flo & 0xFF; ! p += incr; ! ! /* Done */ ! return 0; ! ! Overflow: ! PyErr_SetString(PyExc_OverflowError, ! "float too large to pack with d format"); return -1; } + else { + const char *s = (char*)&x; + int i, incr = 1; ! if ((double_format == ieee_little_endian_format && !le) ! || (double_format == ieee_big_endian_format && le)) { ! p += 7; ! incr = -1; ! } ! ! for (i = 0; i < 8; i++) { ! *p = *s++; ! p += incr; } + return 0; } } double _PyFloat_Unpack4(const unsigned char *p, int le) { ! if (float_format == unknown_format) { ! unsigned char sign; ! int e; ! unsigned int f; ! double x; ! int incr = 1; ! ! if (le) { ! p += 3; ! incr = -1; ! } ! ! /* First byte */ ! sign = (*p >> 7) & 1; ! e = (*p & 0x7F) << 1; ! p += incr; ! ! /* Second byte */ ! e |= (*p >> 7) & 1; ! f = (*p & 0x7F) << 16; ! p += incr; ! ! if (e == 255) { ! PyErr_SetString( ! PyExc_ValueError, ! "can't unpack IEEE 754 special value on non-IEEE platform"); ! return -1; ! } ! ! /* Third byte */ ! f |= *p << 8; ! p += incr; ! ! /* Fourth byte */ ! f |= *p; ! ! x = (double)f / 8388608.0; ! ! /* XXX This sadly ignores Inf/NaN issues */ ! if (e == 0) ! e = -126; ! else { ! x += 1.0; ! e -= 127; ! } ! x = ldexp(x, e); ! if (sign) ! x = -x; ! return x; ! } ! else { ! if ((float_format == ieee_little_endian_format && !le) ! || (float_format == ieee_big_endian_format && le)) { ! char buf[8]; ! char *d = &buf[3]; ! int i; ! ! for (i = 0; i < 4; i++) { ! *d-- = *p++; ! } ! return *(float*)&buf[0]; ! } ! else { ! return *(float*)p; ! } ! } } double _PyFloat_Unpack8(const unsigned char *p, int le) { ! if (double_format == unknown_format) { ! unsigned char sign; ! int e; ! unsigned int fhi, flo; ! double x; ! int incr = 1; ! ! if (le) { ! p += 7; ! incr = -1; ! } ! /* First byte */ ! sign = (*p >> 7) & 1; ! e = (*p & 0x7F) << 4; ! ! p += incr; ! ! /* Second byte */ ! e |= (*p >> 4) & 0xF; ! fhi = (*p & 0xF) << 24; ! p += incr; ! ! if (e == 2047) { ! PyErr_SetString( ! PyExc_ValueError, ! "can't unpack IEEE 754 special value on non-IEEE platform"); ! return -1.0; ! } ! ! /* Third byte */ ! fhi |= *p << 16; ! p += incr; ! ! /* Fourth byte */ ! fhi |= *p << 8; ! p += incr; ! ! /* Fifth byte */ ! fhi |= *p; ! p += incr; ! ! /* Sixth byte */ ! flo = *p << 16; ! p += incr; ! ! /* Seventh byte */ ! flo |= *p << 8; ! p += incr; ! ! /* Eighth byte */ ! flo |= *p; ! x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */ ! x /= 268435456.0; /* 2**28 */ ! ! if (e == 0) ! e = -1022; ! else { ! x += 1.0; ! e -= 1023; ! } ! x = ldexp(x, e); ! ! if (sign) ! x = -x; ! ! return x; ! } ! else { ! if ((double_format == ieee_little_endian_format && !le) ! || (double_format == ieee_big_endian_format && le)) { ! char buf[8]; ! char *d = &buf[7]; ! int i; ! ! for (i = 0; i < 8; i++) { ! *d-- = *p++; ! } ! return *(double*)&buf[0]; ! } ! else { ! return *(double*)p; ! } ! } } Index: Python/pythonrun.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v retrieving revision 2.213 diff -c -r2.213 pythonrun.c *** Python/pythonrun.c 29 Mar 2005 13:36:16 -0000 2.213 --- Python/pythonrun.c 14 Apr 2005 07:43:13 -0000 *************** *** 172,177 **** --- 172,179 ---- if (!_PyInt_Init()) Py_FatalError("Py_Initialize: can't init ints"); + _PyFloat_Init(); + interp->modules = PyDict_New(); if (interp->modules == NULL) Py_FatalError("Py_Initialize: can't make modules dictionary");