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 19 Apr 2005 15:59: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 19 Apr 2005 15:59:46 -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 19 Apr 2005 15:59:59 -0000 *************** *** 980,987 **** --- 980,1118 ---- return Py_BuildValue("(d)", v->ob_fval); } + /* 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; + static float_format_type detected_double_format, detected_float_format; + + static PyObject * + float_getformat(PyTypeObject *v, PyObject* arg) + { + char* s; + float_format_type r; + + if (!PyString_Check(arg)) { + PyErr_Format(PyExc_TypeError, + "__getformat__() argument must be string, not %.500s", + arg->ob_type->tp_name); + return NULL; + } + s = PyString_AS_STRING(arg); + if (strcmp(s, "double") == 0) { + r = double_format; + } + else if (strcmp(s, "float") == 0) { + r = float_format; + } + else { + PyErr_SetString(PyExc_ValueError, + "__getformat__() argument 1 must be " + "'double' or 'float'"); + return NULL; + } + + switch (r) { + case unknown_format: + return PyString_FromString("unknown"); + case ieee_little_endian_format: + return PyString_FromString("IEEE, little-endian"); + case ieee_big_endian_format: + return PyString_FromString("IEEE, big-endian"); + default: + Py_FatalError("insane float_format or double_format"); + return NULL; + } + } + + PyDoc_STRVAR(float_getformat_doc, + "float.__getformat__(typestr) -> string\n" + "\n" + "You probably don't want to use this function. It exists mainly to be\n" + "used in Python's test suite.\n" + "\n" + "typestr must be 'double' or 'float'. This function returns whichever of\n" + "'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n" + "format of floating point numbers used by the C type named by typestr."); + + static PyObject * + float_setformat(PyTypeObject *v, PyObject* args) + { + char* typestr; + char* format; + float_format_type f; + float_format_type detected; + float_format_type *p; + + if (!PyArg_ParseTuple(args, "ss:__setformat__", &typestr, &format)) + return NULL; + + if (strcmp(typestr, "double") == 0) { + p = &double_format; + detected = detected_double_format; + } + else if (strcmp(typestr, "float") == 0) { + p = &float_format; + detected = detected_float_format; + } + else { + PyErr_SetString(PyExc_ValueError, + "__setformat__() argument 1 must " + "be 'double' or 'float'"); + return NULL; + } + + if (strcmp(format, "unknown") == 0) { + f = unknown_format; + } + else if (strcmp(format, "IEEE, little-endian") == 0) { + f = ieee_little_endian_format; + } + else if (strcmp(format, "IEEE, big-endian") == 0) { + f = ieee_big_endian_format; + } + else { + PyErr_SetString(PyExc_ValueError, + "__setformat__() argument 2 must be " + "'unknown', 'IEEE, little-endian' or " + "'IEEE, big-endian'"); + return NULL; + + } + + if (f != unknown_format && f != detected) { + PyErr_Format(PyExc_ValueError, + "can only set %s format to 'unknown' or the " + "detected platform value", typestr); + return NULL; + } + + *p = f; + Py_RETURN_NONE; + } + + PyDoc_STRVAR(float_setformat_doc, + "float.__setformat__(typestr, fmt) -> None\n" + "\n" + "You probably don't want to use this function. It exists mainly to be\n" + "used in Python's test suite.\n" + "\n" + "typestr must be 'double' or 'float'. fmt must be one of 'unknown',\n" + "'IEEE, big-endian' or 'IEEE, little-endian', and in addition can only be\n" + "one of the latter two if it appears to match the underlying C reality.\n" + "\n" + "Overrides the automatic determination of C-level floating point type.\n" + "This affects how floats are converted to and from binary strings."); + static PyMethodDef float_methods[] = { {"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS}, + {"__getformat__", (PyCFunction)float_getformat, + METH_O|METH_CLASS, float_getformat_doc}, + {"__setformat__", (PyCFunction)float_setformat, + METH_VARARGS|METH_CLASS, float_setformat_doc}, {NULL, NULL} /* sentinel */ }; *************** *** 1076,1081 **** --- 1207,1262 ---- }; 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) + detected_double_format = ieee_big_endian_format; + else if (memcmp(&x, "\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0) + detected_double_format = ieee_little_endian_format; + else + detected_double_format = unknown_format; + } + #else + detected_double_format = unknown_format; + #endif + + #if SIZEOF_FLOAT == 4 + { + float y = 16711938.0; + if (memcmp(&y, "\x4b\x7f\x01\x02", 4) == 0) + detected_float_format = ieee_big_endian_format; + else if (memcmp(&y, "\x02\x01\x7f\x4b", 4) == 0) + detected_float_format = ieee_little_endian_format; + else + detected_float_format = unknown_format; + } + #else + detected_float_format = unknown_format; + #endif + + double_format = detected_double_format; + float_format = detected_float_format; + } + + void PyFloat_Fini(void) { PyFloatObject *p; *************** *** 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; } --- 1343,1737 ---- 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 19 Apr 2005 16:00:20 -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"); Index: Lib/test/test_float.py =================================================================== RCS file: Lib/test/test_float.py diff -N Lib/test/test_float.py *** /dev/null 1 Jan 1970 00:00:00 -0000 --- Lib/test/test_float.py 19 Apr 2005 16:00:20 -0000 *************** *** 0 **** --- 1,110 ---- + + import unittest, struct + from test import test_support + + class FormatFunctionsTestCase(unittest.TestCase): + + def setUp(self): + self.save_formats = {'double':float.__getformat__('double'), + 'float':float.__getformat__('float')} + + def tearDown(self): + float.__setformat__('double', self.save_formats['double']) + float.__setformat__('float', self.save_formats['float']) + + def test_getformat(self): + self.assert_(float.__getformat__('double') in + ['unknown', 'IEEE, big-endian', 'IEEE, little-endian']) + self.assert_(float.__getformat__('float') in + ['unknown', 'IEEE, big-endian', 'IEEE, little-endian']) + self.assertRaises(ValueError, float.__getformat__, 'chicken') + self.assertRaises(TypeError, float.__getformat__, 1) + + def test_setformat(self): + for t in 'double', 'float': + float.__setformat__(t, 'unknown') + if self.save_formats[t] == 'IEEE, big-endian': + self.assertRaises(ValueError, float.__setformat__, + t, 'IEEE, little-endian') + elif self.save_formats[t] == 'IEEE, little-endian': + self.assertRaises(ValueError, float.__setformat__, + t, 'IEEE, big-endian') + else: + self.assertRaises(ValueError, float.__setformat__, + t, 'IEEE, big-endian') + self.assertRaises(ValueError, float.__setformat__, + t, 'IEEE, little-endian') + self.assertRaises(ValueError, float.__setformat__, + t, 'chicken') + self.assertRaises(ValueError, float.__setformat__, + 'chicken', 'unknown') + + BE_DOUBLE_INF = '\x7f\xf0\x00\x00\x00\x00\x00\x00' + LE_DOUBLE_INF = ''.join(reversed(BE_DOUBLE_INF)) + BE_DOUBLE_NAN = '\x7f\xf8\x00\x00\x00\x00\x00\x00' + LE_DOUBLE_NAN = ''.join(reversed(BE_DOUBLE_NAN)) + + BE_FLOAT_INF = '\x7f\x80\x00\x00' + LE_FLOAT_INF = ''.join(reversed(BE_FLOAT_INF)) + BE_FLOAT_NAN = '\x7f\xc0\x00\x00' + LE_FLOAT_NAN = ''.join(reversed(BE_FLOAT_NAN)) + + # on non-IEEE platforms, attempting to unpack a bit pattern + # representing an infinity or a NaN should raise an exception. + + class UnknownFormatTestCase(unittest.TestCase): + def setUp(self): + self.save_formats = {'double':float.__getformat__('double'), + 'float':float.__getformat__('float')} + float.__setformat__('double', 'unknown') + float.__setformat__('float', 'unknown') + + def tearDown(self): + float.__setformat__('double', self.save_formats['double']) + float.__setformat__('float', self.save_formats['float']) + + def test_double_specials_dont_unpack(self): + for fmt, data in [('>d', BE_DOUBLE_INF), + ('>d', BE_DOUBLE_NAN), + ('f', BE_FLOAT_INF), + ('>f', BE_FLOAT_NAN), + ('d', BE_DOUBLE_INF), + ('>d', BE_DOUBLE_NAN), + ('f', BE_FLOAT_INF), + ('>f', BE_FLOAT_NAN), + ('