mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +00:00
Support float and double in non-native formats.
These use the ANSI/IEEE standard, which is also used by XDR; so the _xdr module may become obsolete.
This commit is contained in:
parent
9e3fceb5b3
commit
74679b455f
1 changed files with 365 additions and 2 deletions
|
@ -35,6 +35,7 @@ PERFORMANCE OF THIS SOFTWARE.
|
||||||
character strings, and unsigned numbers */
|
character strings, and unsigned numbers */
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
#include "mymath.h"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
@ -200,6 +201,274 @@ get_ulong(v, 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 Signed zero, infinity, underflow, NaN are not handled quite right? */
|
||||||
|
|
||||||
|
static int
|
||||||
|
pack_float(x, p, incr)
|
||||||
|
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 fl;
|
||||||
|
long f;
|
||||||
|
|
||||||
|
if (x < 0) {
|
||||||
|
s = 1;
|
||||||
|
x = -x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s = 0;
|
||||||
|
fl = frexp(x, &e);
|
||||||
|
/* Normalize fl to be in the range [1.0, 2.0) */
|
||||||
|
if (0.5 <= fl && fl < 1.0) {
|
||||||
|
fl *= 2.0;
|
||||||
|
e--;
|
||||||
|
}
|
||||||
|
else if (fl == 0.0) {
|
||||||
|
e = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_SystemError,
|
||||||
|
"frexp() result out of range");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
e += 127;
|
||||||
|
if (e >= 255) {
|
||||||
|
/* XXX 255 itself is reserved for Inf/NaN */
|
||||||
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
|
"float too large to pack with f format");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (e <= 0) {
|
||||||
|
/* XXX Underflow -- could do better, but who cares? */
|
||||||
|
fl = 0.0;
|
||||||
|
e = 0;
|
||||||
|
}
|
||||||
|
if (fl == 0.0) {
|
||||||
|
f = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fl -= 1.0; /* Get rid of leading 1 */
|
||||||
|
fl *= 8388608.0; /* 2**23 */
|
||||||
|
f = (long) floor(fl + 0.5); /* Round */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First byte */
|
||||||
|
*p = (s<<7) | (e>>1);
|
||||||
|
p += incr;
|
||||||
|
|
||||||
|
/* Second byte */
|
||||||
|
*p = ((e&1)<<7) | (f>>16);
|
||||||
|
p += incr;
|
||||||
|
|
||||||
|
/* Third byte */
|
||||||
|
*p = (f>>8) & 0xFF;
|
||||||
|
p += incr;
|
||||||
|
|
||||||
|
/* Fourth byte */
|
||||||
|
*p = f&0xFF;
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pack_double(x, p, incr)
|
||||||
|
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 fl;
|
||||||
|
long fhi, flo;
|
||||||
|
|
||||||
|
if (x < 0) {
|
||||||
|
s = 1;
|
||||||
|
x = -x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
s = 0;
|
||||||
|
fl = frexp(x, &e);
|
||||||
|
/* Normalize fl to be in the range [1.0, 2.0) */
|
||||||
|
if (0.5 <= fl && fl < 1.0) {
|
||||||
|
fl *= 2.0;
|
||||||
|
e--;
|
||||||
|
}
|
||||||
|
else if (fl == 0.0) {
|
||||||
|
e = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_SystemError,
|
||||||
|
"frexp() result out of range");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
e += 1023;
|
||||||
|
if (e >= 2047) {
|
||||||
|
/* XXX 2047 itself is reserved for Inf/NaN */
|
||||||
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
|
"float too large to pack with d format");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (e <= 0) {
|
||||||
|
/* XXX Underflow -- could do better, but who cares? */
|
||||||
|
fl = 0.0;
|
||||||
|
e = 0;
|
||||||
|
}
|
||||||
|
if (fl == 0.0) {
|
||||||
|
fhi = flo = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* fhi receives the high 28 bits; flo the low 24 bits */
|
||||||
|
fl -= 1.0;
|
||||||
|
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 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First byte */
|
||||||
|
*p = (s<<7) | (e>>4);
|
||||||
|
p += incr;
|
||||||
|
|
||||||
|
/* Second byte */
|
||||||
|
*p = ((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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
unpack_float(p, incr)
|
||||||
|
char *p; /* Where the high order byte is */
|
||||||
|
int incr; /* 1 for big-endian; -1 for little-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)
|
||||||
|
x = ldexp(1.0 + x, e - 127);
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
x = -x;
|
||||||
|
|
||||||
|
return PyFloat_FromDouble(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
unpack_double(p, incr)
|
||||||
|
char *p; /* Where the high order byte is */
|
||||||
|
int incr; /* 1 for big-endian; -1 for little-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)
|
||||||
|
x = ldexp(1.0 + x, e - 1023);
|
||||||
|
|
||||||
|
if (s)
|
||||||
|
x = -x;
|
||||||
|
|
||||||
|
return PyFloat_FromDouble(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The translation function for each format character is table driven */
|
/* The translation function for each format character is table driven */
|
||||||
|
|
||||||
typedef struct _formatdef {
|
typedef struct _formatdef {
|
||||||
|
@ -486,6 +755,22 @@ bu_uint(p, f)
|
||||||
return PyLong_FromLong(x);
|
return PyLong_FromLong(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
bu_float(p, f)
|
||||||
|
const char *p;
|
||||||
|
const formatdef *f;
|
||||||
|
{
|
||||||
|
return unpack_float(p, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
bu_double(p, f)
|
||||||
|
const char *p;
|
||||||
|
const formatdef *f;
|
||||||
|
{
|
||||||
|
return unpack_double(p, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bp_int(p, v, f)
|
bp_int(p, v, f)
|
||||||
char *p;
|
char *p;
|
||||||
|
@ -522,6 +807,36 @@ bp_uint(p, v, f)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bp_float(p, v, f)
|
||||||
|
char *p;
|
||||||
|
PyObject *v;
|
||||||
|
const formatdef *f;
|
||||||
|
{
|
||||||
|
double x = PyFloat_AsDouble(v);
|
||||||
|
if (x == -1 && PyErr_Occurred()) {
|
||||||
|
PyErr_SetString(StructError,
|
||||||
|
"required argument is not a float");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pack_float(x, p, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bp_double(p, v, f)
|
||||||
|
char *p;
|
||||||
|
PyObject *v;
|
||||||
|
const formatdef *f;
|
||||||
|
{
|
||||||
|
double x = PyFloat_AsDouble(v);
|
||||||
|
if (x == -1 && PyErr_Occurred()) {
|
||||||
|
PyErr_SetString(StructError,
|
||||||
|
"required argument is not a float");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pack_double(x, p, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static formatdef bigendian_table[] = {
|
static formatdef bigendian_table[] = {
|
||||||
{'x', 1, 0, NULL},
|
{'x', 1, 0, NULL},
|
||||||
{'b', 1, 0, bu_int, bp_int},
|
{'b', 1, 0, bu_int, bp_int},
|
||||||
|
@ -534,7 +849,8 @@ static formatdef bigendian_table[] = {
|
||||||
{'I', 4, 0, bu_uint, bp_uint},
|
{'I', 4, 0, bu_uint, bp_uint},
|
||||||
{'l', 4, 0, bu_int, bp_int},
|
{'l', 4, 0, bu_int, bp_int},
|
||||||
{'L', 4, 0, bu_uint, bp_uint},
|
{'L', 4, 0, bu_uint, bp_uint},
|
||||||
/* No float and double! */
|
{'f', 4, 0, bu_float, bp_float},
|
||||||
|
{'d', 8, 0, bu_double, bp_double},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -572,6 +888,22 @@ lu_uint(p, f)
|
||||||
return PyLong_FromLong(x);
|
return PyLong_FromLong(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
lu_float(p, f)
|
||||||
|
const char *p;
|
||||||
|
const formatdef *f;
|
||||||
|
{
|
||||||
|
return unpack_float(p+3, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
lu_double(p, f)
|
||||||
|
const char *p;
|
||||||
|
const formatdef *f;
|
||||||
|
{
|
||||||
|
return unpack_double(p+7, -1);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lp_int(p, v, f)
|
lp_int(p, v, f)
|
||||||
char *p;
|
char *p;
|
||||||
|
@ -608,6 +940,36 @@ lp_uint(p, v, f)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lp_float(p, v, f)
|
||||||
|
char *p;
|
||||||
|
PyObject *v;
|
||||||
|
const formatdef *f;
|
||||||
|
{
|
||||||
|
double x = PyFloat_AsDouble(v);
|
||||||
|
if (x == -1 && PyErr_Occurred()) {
|
||||||
|
PyErr_SetString(StructError,
|
||||||
|
"required argument is not a float");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pack_float(x, p+3, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lp_double(p, v, f)
|
||||||
|
char *p;
|
||||||
|
PyObject *v;
|
||||||
|
const formatdef *f;
|
||||||
|
{
|
||||||
|
double x = PyFloat_AsDouble(v);
|
||||||
|
if (x == -1 && PyErr_Occurred()) {
|
||||||
|
PyErr_SetString(StructError,
|
||||||
|
"required argument is not a float");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pack_double(x, p+7, -1);
|
||||||
|
}
|
||||||
|
|
||||||
static formatdef lilendian_table[] = {
|
static formatdef lilendian_table[] = {
|
||||||
{'x', 1, 0, NULL},
|
{'x', 1, 0, NULL},
|
||||||
{'b', 1, 0, lu_int, lp_int},
|
{'b', 1, 0, lu_int, lp_int},
|
||||||
|
@ -620,7 +982,8 @@ static formatdef lilendian_table[] = {
|
||||||
{'I', 4, 0, lu_uint, lp_uint},
|
{'I', 4, 0, lu_uint, lp_uint},
|
||||||
{'l', 4, 0, lu_int, lp_int},
|
{'l', 4, 0, lu_int, lp_int},
|
||||||
{'L', 4, 0, lu_uint, lp_uint},
|
{'L', 4, 0, lu_uint, lp_uint},
|
||||||
/* No float and double! */
|
{'f', 4, 0, lu_float, lp_float},
|
||||||
|
{'d', 8, 0, lu_double, lp_double},
|
||||||
{0}
|
{0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue