summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/floatobject.h29
-rw-r--r--Include/pythonrun.h1
-rw-r--r--Lib/test/test_float.py110
-rw-r--r--Objects/floatobject.c748
-rw-r--r--Python/pythonrun.c2
5 files changed, 639 insertions, 251 deletions
diff --git a/Include/floatobject.h b/Include/floatobject.h
index 9a2066f..f695de8 100644
--- a/Include/floatobject.h
+++ b/Include/floatobject.h
@@ -55,13 +55,18 @@ PyAPI_FUNC(void) PyFloat_AsString(char*, PyFloatObject *v);
* 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).
+ * 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,8 +75,9 @@ PyAPI_FUNC(void) PyFloat_AsString(char*, PyFloatObject *v);
* 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.
+ * 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,9 +87,8 @@ PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le);
* 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.
+ * 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);
diff --git a/Include/pythonrun.h b/Include/pythonrun.h
index 33497ce..4afab88 100644
--- a/Include/pythonrun.h
+++ b/Include/pythonrun.h
@@ -105,6 +105,7 @@ PyAPI_FUNC(void) _PyExc_Init(void);
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);
diff --git a/Lib/test/test_float.py b/Lib/test/test_float.py
new file mode 100644
index 0000000..cf8c094
--- /dev/null
+++ b/Lib/test/test_float.py
@@ -0,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),
+ ('<d', LE_DOUBLE_INF),
+ ('<d', LE_DOUBLE_NAN)]:
+ self.assertRaises(ValueError, struct.unpack, fmt, data)
+
+ def test_float_specials_dont_unpack(self):
+ for fmt, data in [('>f', BE_FLOAT_INF),
+ ('>f', BE_FLOAT_NAN),
+ ('<f', LE_FLOAT_INF),
+ ('<f', LE_FLOAT_NAN)]:
+ self.assertRaises(ValueError, struct.unpack, fmt, data)
+
+
+# on an IEEE platform, all we guarantee is that bit patterns
+# representing infinities or NaNs do not raise an exception; all else
+# is accident (today).
+
+class IEEEFormatTestCase(unittest.TestCase):
+ if float.__getformat__("double").startswith("IEEE"):
+ def test_double_specials_do_unpack(self):
+ for fmt, data in [('>d', BE_DOUBLE_INF),
+ ('>d', BE_DOUBLE_NAN),
+ ('<d', LE_DOUBLE_INF),
+ ('<d', LE_DOUBLE_NAN)]:
+ struct.unpack(fmt, data)
+
+ if float.__getformat__("float").startswith("IEEE"):
+ def test_float_specials_do_unpack(self):
+ for fmt, data in [('>f', BE_FLOAT_INF),
+ ('>f', BE_FLOAT_NAN),
+ ('<f', LE_FLOAT_INF),
+ ('<f', LE_FLOAT_NAN)]:
+ struct.unpack(fmt, data)
+
+
+def test_main():
+ test_support.run_unittest(
+ FormatFunctionsTestCase,
+ UnknownFormatTestCase,
+ IEEEFormatTestCase)
+
+if __name__ == '__main__':
+ test_main()
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 55f43cb..c95b5c9 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -983,8 +983,139 @@ float_getnewargs(PyFloatObject *v)
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 */
};
@@ -1079,6 +1210,56 @@ PyTypeObject PyFloat_Type = {
};
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;
@@ -1165,306 +1346,395 @@ PyFloat_Fini(void)
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;
+ if (float_format == unknown_format) {
+ unsigned char sign;
+ int e;
+ double f;
+ unsigned int fbits;
+ int incr = 1;
+
+ if (le) {
+ p += 3;
+ incr = -1;
+ }
- f = frexp(x, &e);
+ if (x < 0) {
+ sign = 1;
+ x = -x;
+ }
+ else
+ sign = 0;
- /* 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;
- }
+ f = frexp(x, &e);
- 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 */
- }
+ /* 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;
+ }
- 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)
+ 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;
+ /* First byte */
+ *p = (sign << 7) | (e >> 1);
+ p += incr;
- /* Second byte */
- *p = (char) (((e & 1) << 7) | (fbits >> 16));
- p += incr;
+ /* Second byte */
+ *p = (char) (((e & 1) << 7) | (fbits >> 16));
+ p += incr;
- /* Third byte */
- *p = (fbits >> 8) & 0xFF;
- p += incr;
+ /* Third byte */
+ *p = (fbits >> 8) & 0xFF;
+ p += incr;
- /* Fourth byte */
- *p = fbits & 0xFF;
+ /* Fourth byte */
+ *p = fbits & 0xFF;
- /* Done */
- return 0;
+ /* Done */
+ return 0;
- Overflow:
- PyErr_SetString(PyExc_OverflowError,
- "float too large to pack with f format");
- return -1;
+ 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)
{
- unsigned char sign;
- int e;
- double f;
- unsigned int fhi, flo;
- int incr = 1;
+ 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 (le) {
- p += 7;
- incr = -1;
- }
+ if (x < 0) {
+ sign = 1;
+ x = -x;
+ }
+ else
+ sign = 0;
- if (x < 0) {
- sign = 1;
- x = -x;
- }
- else
- sign = 0;
+ f = frexp(x, &e);
- 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;
+ }
- /* 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 */
+ }
- 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;
+ /* 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;
+ /* First byte */
+ *p = (sign << 7) | (e >> 4);
+ p += incr;
- /* Second byte */
- *p = (unsigned char) (((e & 0xF) << 4) | (fhi >> 24));
- p += incr;
+ /* Second byte */
+ *p = (unsigned char) (((e & 0xF) << 4) | (fhi >> 24));
+ p += incr;
- /* Third byte */
- *p = (fhi >> 16) & 0xFF;
- p += incr;
+ /* Third byte */
+ *p = (fhi >> 16) & 0xFF;
+ p += incr;
- /* Fourth byte */
- *p = (fhi >> 8) & 0xFF;
- p += incr;
+ /* Fourth byte */
+ *p = (fhi >> 8) & 0xFF;
+ p += incr;
- /* Fifth byte */
- *p = fhi & 0xFF;
- p += incr;
+ /* Fifth byte */
+ *p = fhi & 0xFF;
+ p += incr;
- /* Sixth byte */
- *p = (flo >> 16) & 0xFF;
- p += incr;
+ /* Sixth byte */
+ *p = (flo >> 16) & 0xFF;
+ p += incr;
- /* Seventh byte */
- *p = (flo >> 8) & 0xFF;
- p += incr;
+ /* Seventh byte */
+ *p = (flo >> 8) & 0xFF;
+ p += incr;
- /* Eighth byte */
- *p = flo & 0xFF;
- p += incr;
+ /* Eighth byte */
+ *p = flo & 0xFF;
+ p += incr;
- /* Done */
- return 0;
+ /* 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;
- Overflow:
- PyErr_SetString(PyExc_OverflowError,
- "float too large to pack with d format");
- return -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)
{
- unsigned char sign;
- int e;
- unsigned int f;
- double x;
- int incr = 1;
+ if (float_format == unknown_format) {
+ unsigned char sign;
+ int e;
+ unsigned int f;
+ double x;
+ int incr = 1;
+
+ if (le) {
+ p += 3;
+ 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;
+ }
- /* First byte */
- sign = (*p >> 7) & 1;
- e = (*p & 0x7F) << 1;
- p += incr;
+ /* Third byte */
+ f |= *p << 8;
+ p += incr;
- /* Second byte */
- e |= (*p >> 7) & 1;
- f = (*p & 0x7F) << 16;
- p += incr;
+ /* Fourth byte */
+ f |= *p;
- /* Third byte */
- f |= *p << 8;
- p += incr;
+ x = (double)f / 8388608.0;
- /* Fourth byte */
- f |= *p;
+ /* XXX This sadly ignores Inf/NaN issues */
+ if (e == 0)
+ e = -126;
+ else {
+ x += 1.0;
+ e -= 127;
+ }
+ x = ldexp(x, e);
- x = (double)f / 8388608.0;
+ if (sign)
+ x = -x;
- /* XXX This sadly ignores Inf/NaN issues */
- if (e == 0)
- e = -126;
- else {
- x += 1.0;
- e -= 127;
+ return x;
}
- 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)
{
- unsigned char sign;
- int e;
- unsigned int fhi, flo;
- double x;
- int incr = 1;
+ 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;
+ }
- 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;
+ }
- /* First byte */
- sign = (*p >> 7) & 1;
- e = (*p & 0x7F) << 4;
- p += incr;
+ /* Third byte */
+ fhi |= *p << 16;
+ p += incr;
- /* Second byte */
- e |= (*p >> 4) & 0xF;
- fhi = (*p & 0xF) << 24;
- p += incr;
+ /* Fourth byte */
+ fhi |= *p << 8;
+ p += incr;
- /* Third byte */
- fhi |= *p << 16;
- p += incr;
+ /* Fifth byte */
+ fhi |= *p;
+ p += incr;
- /* Fourth byte */
- fhi |= *p << 8;
- p += incr;
+ /* Sixth byte */
+ flo = *p << 16;
+ p += incr;
- /* Fifth byte */
- fhi |= *p;
- p += incr;
+ /* Seventh byte */
+ flo |= *p << 8;
+ p += incr;
- /* Sixth byte */
- flo = *p << 16;
- p += incr;
+ /* Eighth byte */
+ flo |= *p;
- /* Seventh byte */
- flo |= *p << 8;
- p += incr;
+ x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */
+ x /= 268435456.0; /* 2**28 */
- /* Eighth byte */
- flo |= *p;
+ if (e == 0)
+ e = -1022;
+ else {
+ x += 1.0;
+ e -= 1023;
+ }
+ x = ldexp(x, e);
- x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */
- x /= 268435456.0; /* 2**28 */
+ if (sign)
+ x = -x;
- /* XXX This sadly ignores Inf/NaN */
- if (e == 0)
- e = -1022;
+ return x;
+ }
else {
- x += 1.0;
- e -= 1023;
+ 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;
+ }
}
- x = ldexp(x, e);
-
- if (sign)
- x = -x;
-
- return x;
}
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index f629709..0ac46f0 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -172,6 +172,8 @@ Py_InitializeEx(int install_sigs)
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");