+/* Same as the above, but we return *half* of a 64-bit double, depending on whether wanthigh is true (high half) or false (low half).
+ */
+static int32 construct_double(int wanthigh, int signbit, double intv, double fracv, int expo)
+{
+ double absval = (intv + fracv) * pow10_cheap(expo);
+ int32 sign = (signbit ? 0x80000000 : 0x0);
+ double mant;
+ uint32 fhi, flo;
+
+ if (isinf(absval)) {
+ goto Infinity;
+ }
+ if (isnan(absval)) {
+ goto NotANumber;
+ }
+
+ mant = frexp(absval, &expo);
+
+ /* Normalize mantissa to be in the range [1.0, 2.0) */
+ if (0.5 <= mant && mant < 1.0) {
+ mant *= 2.0;
+ expo--;
+ }
+ else if (mant == 0.0) {
+ expo = 0;
+ }
+ else {
+ goto Infinity;
+ }
+
+ if (expo >= 1024) {
+ goto Infinity;
+ }
+ else if (expo < -1022) {
+ /* Denormalized (very small) number */
+ mant = ldexp(mant, 1022 + expo);
+ expo = 0;
+ }
+ else if (!(expo == 0 && mant == 0.0)) {
+ expo += 1023;
+ mant -= 1.0; /* Get rid of leading 1 */
+ }
+
+ /* fhi receives the high 28 bits; flo the low 24 bits (total 52 bits) */
+ mant *= 268435456.0; /* 2^28 */
+ fhi = (uint32)mant; /* Truncate */
+ mant -= (double)fhi;
+ mant *= 16777216.0; /* 2^24 */
+ flo = (uint32)(mant+0.5); /* Round */
+
+ if (flo >> 24) {
+ /* The carry propagated out of a string of 24 1 bits. */
+ flo = 0;
+ fhi++;
+ if (fhi >> 28) {
+ /* And it also propagated out of the next 28 bits. */
+ fhi = 0;
+ expo++;
+ if (expo >= 2047) {
+ goto Infinity;
+ }
+ }
+ }
+
+ /* At this point, expo is less than 2^11; fhi is less than 2^28; flo is less than 2^24; none are negative. */
+ if (wanthigh)
+ return (sign) | ((int32)(expo << 20)) | ((int32)(fhi >> 8));
+ else
+ return (int32)((fhi & 0xFF) << 24) | (int32)(flo);
+
+ Infinity:
+ if (wanthigh)
+ return sign | 0x7FF00000;
+ else
+ return 0x00000000;
+
+ NotANumber:
+ if (wanthigh)
+ return sign | 0x7FF80000;
+ else
+ return 0x00000001;
+}
+