Ok, ok, I've fixed gradual underflow on packing too.
Still don't know what to do with Inf/NaN, so I raise an exception on pack(), and something random decided by ldexp() will happen on unpack().
This commit is contained in:
parent
6083f0e9ce
commit
4ccc531f34
|
@ -207,7 +207,7 @@ get_ulong(v, p)
|
||||||
Point Arithmetic). See the following URL:
|
Point Arithmetic). See the following URL:
|
||||||
http://www.psc.edu/general/software/packages/ieee/ieee.html */
|
http://www.psc.edu/general/software/packages/ieee/ieee.html */
|
||||||
|
|
||||||
/* XXX Signed zero, infinity, underflow, NaN are not handled quite right? */
|
/* XXX Inf/NaN are not handled quite right (but underflow is!) */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pack_float(x, p, incr)
|
pack_float(x, p, incr)
|
||||||
|
@ -217,8 +217,8 @@ pack_float(x, p, incr)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
int e;
|
int e;
|
||||||
double fl;
|
double f;
|
||||||
long f;
|
long fbits;
|
||||||
|
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
s = 1;
|
s = 1;
|
||||||
|
@ -226,13 +226,15 @@ pack_float(x, p, incr)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
s = 0;
|
s = 0;
|
||||||
fl = frexp(x, &e);
|
|
||||||
/* Normalize fl to be in the range [1.0, 2.0) */
|
f = frexp(x, &e);
|
||||||
if (0.5 <= fl && fl < 1.0) {
|
|
||||||
fl *= 2.0;
|
/* Normalize f to be in the range [1.0, 2.0) */
|
||||||
|
if (0.5 <= f && f < 1.0) {
|
||||||
|
f *= 2.0;
|
||||||
e--;
|
e--;
|
||||||
}
|
}
|
||||||
else if (fl == 0.0) {
|
else if (f == 0.0) {
|
||||||
e = 0;
|
e = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -240,41 +242,40 @@ pack_float(x, p, incr)
|
||||||
"frexp() result out of range");
|
"frexp() result out of range");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
e += 127;
|
|
||||||
if (e >= 255) {
|
if (e >= 128) {
|
||||||
/* XXX 255 itself is reserved for Inf/NaN */
|
/* XXX 128 itself is reserved for Inf/NaN */
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"float too large to pack with f format");
|
"float too large to pack with f format");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (e <= 0) {
|
else if (e < -126) {
|
||||||
/* XXX Underflow -- could do better, but who cares? */
|
/* Gradual underflow */
|
||||||
fl = 0.0;
|
f = ldexp(f, 126 + e);
|
||||||
e = 0;
|
e = 0;
|
||||||
}
|
}
|
||||||
if (fl == 0.0) {
|
|
||||||
f = 0;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
fl -= 1.0; /* Get rid of leading 1 */
|
e += 127;
|
||||||
fl *= 8388608.0; /* 2**23 */
|
f -= 1.0; /* Get rid of leading 1 */
|
||||||
f = (long) floor(fl + 0.5); /* Round */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f *= 8388608.0; /* 2**23 */
|
||||||
|
fbits = (long) floor(f + 0.5); /* Round */
|
||||||
|
|
||||||
/* First byte */
|
/* First byte */
|
||||||
*p = (s<<7) | (e>>1);
|
*p = (s<<7) | (e>>1);
|
||||||
p += incr;
|
p += incr;
|
||||||
|
|
||||||
/* Second byte */
|
/* Second byte */
|
||||||
*p = ((e&1)<<7) | (f>>16);
|
*p = ((e&1)<<7) | (fbits>>16);
|
||||||
p += incr;
|
p += incr;
|
||||||
|
|
||||||
/* Third byte */
|
/* Third byte */
|
||||||
*p = (f>>8) & 0xFF;
|
*p = (fbits>>8) & 0xFF;
|
||||||
p += incr;
|
p += incr;
|
||||||
|
|
||||||
/* Fourth byte */
|
/* Fourth byte */
|
||||||
*p = f&0xFF;
|
*p = fbits&0xFF;
|
||||||
|
|
||||||
/* Done */
|
/* Done */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -288,7 +289,7 @@ pack_double(x, p, incr)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
int e;
|
int e;
|
||||||
double fl;
|
double f;
|
||||||
long fhi, flo;
|
long fhi, flo;
|
||||||
|
|
||||||
if (x < 0) {
|
if (x < 0) {
|
||||||
|
@ -297,13 +298,15 @@ pack_double(x, p, incr)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
s = 0;
|
s = 0;
|
||||||
fl = frexp(x, &e);
|
|
||||||
/* Normalize fl to be in the range [1.0, 2.0) */
|
f = frexp(x, &e);
|
||||||
if (0.5 <= fl && fl < 1.0) {
|
|
||||||
fl *= 2.0;
|
/* Normalize f to be in the range [1.0, 2.0) */
|
||||||
|
if (0.5 <= f && f < 1.0) {
|
||||||
|
f *= 2.0;
|
||||||
e--;
|
e--;
|
||||||
}
|
}
|
||||||
else if (fl == 0.0) {
|
else if (f == 0.0) {
|
||||||
e = 0;
|
e = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -311,31 +314,30 @@ pack_double(x, p, incr)
|
||||||
"frexp() result out of range");
|
"frexp() result out of range");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
e += 1023;
|
|
||||||
if (e >= 2047) {
|
if (e >= 1024) {
|
||||||
/* XXX 2047 itself is reserved for Inf/NaN */
|
/* XXX 1024 itself is reserved for Inf/NaN */
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"float too large to pack with d format");
|
"float too large to pack with d format");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (e <= 0) {
|
else if (e < -1022) {
|
||||||
/* XXX Underflow -- could do better, but who cares? */
|
/* Gradual underflow */
|
||||||
fl = 0.0;
|
f = ldexp(f, 1022 + e);
|
||||||
e = 0;
|
e = 0;
|
||||||
}
|
}
|
||||||
if (fl == 0.0) {
|
|
||||||
fhi = flo = 0;
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
/* fhi receives the high 28 bits; flo the low 24 bits */
|
e += 1023;
|
||||||
fl -= 1.0;
|
f -= 1.0; /* Get rid of leading 1 */
|
||||||
fl *= 268435456.0; /* 2**28 */
|
|
||||||
fhi = (long) floor(fl); /* Truncate */
|
|
||||||
fl -= (double)fhi;
|
|
||||||
fl *= 16777216.0; /* 2**24 */
|
|
||||||
flo = (long) floor(fl + 0.5); /* Round */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
|
||||||
|
f *= 268435456.0; /* 2**28 */
|
||||||
|
fhi = (long) floor(f); /* Truncate */
|
||||||
|
f -= (double)fhi;
|
||||||
|
f *= 16777216.0; /* 2**24 */
|
||||||
|
flo = (long) floor(f + 0.5); /* Round */
|
||||||
|
|
||||||
/* First byte */
|
/* First byte */
|
||||||
*p = (s<<7) | (e>>4);
|
*p = (s<<7) | (e>>4);
|
||||||
p += incr;
|
p += incr;
|
||||||
|
|
Loading…
Reference in New Issue