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.
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 @@
 
 /* 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 @@
 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 @@
 				"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 @@
 				"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 @@
 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 @@
 				"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 @@
 				"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[] = {