diff options
author | Tim Peters <tim.peters@gmail.com> | 2003-03-20 20:53:32 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2003-03-20 20:53:32 (GMT) |
commit | 9905b943f79a03741b062c82bdf96a078df303e4 (patch) | |
tree | 2783e7140997093ce911bac91d65048b53049144 /Modules/structmodule.c | |
parent | d50ade68ec240ea8ea12604809d8c70985263dce (diff) | |
download | cpython-9905b943f79a03741b062c82bdf96a078df303e4.zip cpython-9905b943f79a03741b062c82bdf96a078df303e4.tar.gz cpython-9905b943f79a03741b062c82bdf96a078df303e4.tar.bz2 |
New private API functions _PyFloat_{Pack,Unpack}(4,8}. This is a
refactoring to get all the duplicates of this delicate code out of the
cPickle and struct modules.
Diffstat (limited to 'Modules/structmodule.c')
-rw-r--r-- | Modules/structmodule.c | 310 |
1 files changed, 18 insertions, 292 deletions
diff --git a/Modules/structmodule.c b/Modules/structmodule.c index 2210c33..e4e1eb5 100644 --- a/Modules/structmodule.c +++ b/Modules/structmodule.c @@ -185,301 +185,27 @@ get_ulonglong(PyObject *v, unsigned LONG_LONG *p) /* Floating point helpers */ -/* These use ANSI/IEEE Standard 754-1985 (Standard for Binary Floating - Point Arithmetic). See the following URL: - http://www.psc.edu/general/software/packages/ieee/ieee.html */ - -/* XXX Inf/NaN are not handled quite right (but underflow is!) */ - -static int -pack_float(double x, /* The number to pack */ - char *p, /* Where to pack the high order byte */ - int incr) /* 1 for big-endian; -1 for little-endian */ -{ - int s; - int e; - double f; - long fbits; - - if (x < 0) { - s = 1; - x = -x; - } - else - s = 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 = (long) floor(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 = (s<<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; -} - -static int -pack_double(double x, /* The number to pack */ - char *p, /* Where to pack the high order byte */ - int incr) /* 1 for big-endian; -1 for little-endian */ -{ - int s; - int e; - double f; - long fhi, flo; - - if (x < 0) { - s = 1; - x = -x; - } - else - s = 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 = (long) floor(f); /* Truncate */ - assert(fhi < 268435456); - - f -= (double)fhi; - f *= 16777216.0; /* 2**24 */ - flo = (long) floor(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 = (s<<7) | (e>>4); - p += incr; - - /* Second byte */ - *p = (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; -} - static PyObject * -unpack_float(const char *p, /* Where the high order byte is */ - int incr) /* 1 for big-endian; -1 for little-endian */ +unpack_float(const char *p, /* start of 4-byte string */ + int le) /* true for little-endian, false for big-endian */ { - int s; - int e; - long f; double x; - /* First byte */ - s = (*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 & 0xFF) << 8; - p += incr; - - /* Fourth byte */ - f |= *p & 0xFF; - - 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 (s) - x = -x; - + x = _PyFloat_Unpack4((unsigned char *)p, le); + if (x == -1.0 && PyErr_Occurred()) + return NULL; return PyFloat_FromDouble(x); } static PyObject * -unpack_double(const char *p, /* Where the high order byte is */ - int incr) /* 1 for big-endian; -1 for little-endian */ +unpack_double(const char *p, /* start of 8-byte string */ + int le) /* true for little-endian, false for big-endian */ { - int s; - int e; - long fhi, flo; double x; - /* First byte */ - s = (*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 & 0xFF) << 16; - p += incr; - - /* Fourth byte */ - fhi |= (*p & 0xFF) << 8; - p += incr; - - /* Fifth byte */ - fhi |= *p & 0xFF; - p += incr; - - /* Sixth byte */ - flo = (*p & 0xFF) << 16; - p += incr; - - /* Seventh byte */ - flo |= (*p & 0xFF) << 8; - p += incr; - - /* Eighth byte */ - flo |= *p & 0xFF; - p += incr; - - 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 (s) - x = -x; - + x = _PyFloat_Unpack8((unsigned char *)p, le); + if (x == -1.0 && PyErr_Occurred()) + return NULL; return PyFloat_FromDouble(x); } @@ -887,13 +613,13 @@ bu_ulonglong(const char *p, const formatdef *f) static PyObject * bu_float(const char *p, const formatdef *f) { - return unpack_float(p, 1); + return unpack_float(p, 0); } static PyObject * bu_double(const char *p, const formatdef *f) { - return unpack_double(p, 1); + return unpack_double(p, 0); } static int @@ -967,7 +693,7 @@ bp_float(char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - return pack_float(x, p, 1); + return _PyFloat_Pack4(x, (unsigned char *)p, 0); } static int @@ -979,7 +705,7 @@ bp_double(char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - return pack_double(x, p, 1); + return _PyFloat_Pack8(x, (unsigned char *)p, 0); } static formatdef bigendian_table[] = { @@ -1053,13 +779,13 @@ lu_ulonglong(const char *p, const formatdef *f) static PyObject * lu_float(const char *p, const formatdef *f) { - return unpack_float(p+3, -1); + return unpack_float(p, 1); } static PyObject * lu_double(const char *p, const formatdef *f) { - return unpack_double(p+7, -1); + return unpack_double(p, 1); } static int @@ -1133,7 +859,7 @@ lp_float(char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - return pack_float(x, p+3, -1); + return _PyFloat_Pack4(x, (unsigned char *)p, 1); } static int @@ -1145,7 +871,7 @@ lp_double(char *p, PyObject *v, const formatdef *f) "required argument is not a float"); return -1; } - return pack_double(x, p+7, -1); + return _PyFloat_Pack8(x, (unsigned char *)p, 1); } static formatdef lilendian_table[] = { |