mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
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.
This commit is contained in:
parent
d50ade68ec
commit
9905b943f7
4 changed files with 382 additions and 446 deletions
|
@ -904,3 +904,316 @@ PyFloat_Fini(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h.
|
||||
*
|
||||
* TODO: On platforms that use the standard IEEE-754 single and double
|
||||
* formats natively, these routines could simply copy the bytes.
|
||||
*/
|
||||
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 = (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 = (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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue