#include "bits.h"
#include "buf.h"
+#include "maths.h"
/*----- Formatting primitives ---------------------------------------------*/
* otherwise it's a signalling NaN.
*/
+/* --- @k64_to_f64@ --- *
+ *
+ * Arguments: @double *x_out@ = where to put the result
+ * @kludge64 k@ = a 64-bit encoding of a floating-point value
+ *
+ * Returns: Zero on success, @-1@ on failure.
+ *
+ * Use: Decodes @k@ as a `binary64' value. See `buf_getf64' for the
+ * caveats.
+ */
+
+static int k64_to_f64(double *x_out, kludge64 k)
+{
+ uint32 lo, hi, t;
+ int s, e; double x;
+
+ /* We're using the IEEE 754 `binary64' format: see `float_to_k64' above. */
+
+ /* Pick the encoded number apart. */
+ hi = HI64(k); lo = LO64(k);
+ s = (hi >> 31)&1; e = (hi >> 20)&0x07ff; t = hi&0x000fffff;
+
+ /* Deal with various special cases. */
+ if (e == 2047) {
+ /* Maximum exponent indicates (positive or negative) infinity or NaN. */
+
+ if (t || lo) {
+ /* It's a NaN. We're not going to be picky about which one. If we
+ * can't represent it then we'll just have to fail.
+ */
+
+#ifdef NAN
+ x = NAN;
+#else
+ return (-1);
+#endif
+ } else {
+ /* It's an infinity. If we don't have one of those to hand, then pick
+ * something really big.
+ */
+
+#ifdef INFINITY
+ x = s ? -INFINITY : INFINITY;
+#else
+ x = s ? -DBL_MAX : DBL_MAX;
+#endif
+ }
+ } else {
+ /* It's a finite number, though maybe it's weird in some way. */
+
+ if (e == 0) {
+ /* Minimum exponent indicates zero or a subnormal number. The
+ * subnormal exponent is a sentinel value that shouldn't be taken
+ * literally, so we should fix that. If the number is actually zero
+ * then the exponent won't matter much so don't bother checking.
+ */
+
+ e = 1;
+ } else {
+ /* It's a normal number. In which case there's an implicit bit which
+ * we can now set.
+ */
+
+ t |= 0x00100000;
+ }
+
+ /* All that remains is to stuff the significant and exponent into a
+ * floating point number. We'll have to do this in pieces, and we'll
+ * lean on the floating-point machinery to do rounding correctly.
+ */
+ x = ldexp(t, e - 1043) + ldexp(lo, e - 1075);
+ if (s) x = -x;
+ }
+
+ /* And we're done. */
+ *x_out = x; return (0);
+}
+
/* --- @f64_to_k64@ --- *
*
* Arguments: @double x@ = a floating-point number
/* Some machinery before we start. */
-#ifdef isnan
-# define NANP(x) isnan(x)
-#else
-# define NANP(x) (!((x) == (x)))
-#endif
-
-#ifdef isinf
-# define INFP(x) isinf(x)
-#else
-# define INFP(x) ((x) > DBL_MAX || (x) < -DBL_MAX)
-#endif
-
-#ifdef signbit
-# define NEGP(x) signbit(x)
-#else
-# define NEGP(x) ((x) < 0) /* incorrect for negative zero! */
-#endif
-
if (NANP(x)) {
/* A NaN. */
hi = 0x7ff80000; lo = 0;
/* Convert to external format and go home. */
SET64(k, hi, lo); return (k);
-
-#undef NANP
-#undef INFP
-#undef NEGP
-}
-
-/* --- @k64_to_f64@ --- *
- *
- * Arguments: @double *x_out@ = where to put the result
- * @kludge64 k@ = a 64-bit encoding of a floating-point value
- *
- * Returns: Zero on success, @-1@ on failure.
- *
- * Use: Decodes @k@ as a `binary64' value. See `buf_getf64' for the
- * caveats.
- */
-
-static int k64_to_f64(double *x_out, kludge64 k)
-{
- uint32 lo, hi, t;
- int s, e; double x;
-
- /* We're using the IEEE 754 `binary64' format: see `float_to_k64' above. */
-
- /* Pick the encoded number apart. */
- hi = HI64(k); lo = LO64(k);
- s = (hi >> 31)&1; e = (hi >> 20)&0x07ff; t = hi&0x000fffff;
-
- /* Deal with various special cases. */
- if (e == 2047) {
- /* Maximum exponent indicates (positive or negative) infinity or NaN. */
-
- if (t || lo) {
- /* It's a NaN. We're not going to be picky about which one. If we
- * can't represent it then we'll just have to fail.
- */
-
-#ifdef NAN
- x = NAN;
-#else
- return (-1);
-#endif
- } else {
- /* It's an infinity. If we don't have one of those to hand, then pick
- * something really big.
- */
-
-#ifdef INFINITY
- x = s ? -INFINITY : INFINITY;
-#else
- x = s ? -DBL_MAX : DBL_MAX;
-#endif
- }
- } else {
- /* It's a finite number, though maybe it's weird in some way. */
-
- if (e == 0) {
- /* Minimum exponent indicates zero or a subnormal number. The
- * subnormal exponent is a sentinel value that shouldn't be taken
- * literally, so we should fix that. If the number is actually zero
- * then the exponent won't matter much so don't bother checking.
- */
-
- e = 1;
- } else {
- /* It's a normal number. In which case there's an implicit bit which
- * we can now set.
- */
-
- t |= 0x00100000;
- }
-
- /* All that remains is to stuff the significant and exponent into a
- * floating point number. We'll have to do this in pieces, and we'll
- * lean on the floating-point machinery to do rounding correctly.
- */
- x = ldexp(t, e - 1043) + ldexp(lo, e - 1075);
- if (s) x = -x;
- }
-
- /* And we're done. */
- *x_out = x; return (0);
}
/*----- External functions ------------------------------------------------*/
-/* --- @buf_putf64{,b,l} --- *
- *
- * Arguments: @buf *b@ = a buffer to write to
- * @double x@ = a number to write
- *
- * Returns: Zero on success, @-1@ on failure (and the buffer is broken).
- *
- * On C89, this function can't detect negative zero so these
- * will be silently written as positive zero.
- *
- * This function doesn't distinguish NaNs. Any NaN is written
- * as a quiet NaN with all payload bits zero.
- *
- * A finite value with too large a magnitude to be represented
- * is rounded to the appropriate infinity. Other finite values
- * are rounded as necessary, in the usual IEEE 754 round-to-
- * nearest-or-even way.
- */
-
-int buf_putf64(buf *b, double x)
- { return (buf_putk64(b, f64_to_k64(x))); }
-int buf_putf64b(buf *b, double x)
- { return (buf_putk64b(b, f64_to_k64(x))); }
-int buf_putf64l(buf *b, double x)
- { return (buf_putk64l(b, f64_to_k64(x))); }
-
-/* --- @buf_getf64{,b,l} --- *
+/* --- @buf_getf64{,l,b} --- *
*
* Arguments: @buf *b@ = a buffer to read from
* @double *x_out@ = where to put the result
if (k64_to_f64(x_out, k)) { b->f |= BF_BROKEN; return (-1); }
return (0);
}
-int buf_getf64b(buf *b, double *x_out)
+
+int buf_getf64l(buf *b, double *x_out)
{
kludge64 k;
- if (buf_getk64b(b, &k)) return (-1);
+ if (buf_getk64l(b, &k)) return (-1);
if (k64_to_f64(x_out, k)) { b->f |= BF_BROKEN; return (-1); }
return (0);
}
-int buf_getf64l(buf *b, double *x_out)
+
+int buf_getf64b(buf *b, double *x_out)
{
kludge64 k;
- if (buf_getk64l(b, &k)) return (-1);
+ if (buf_getk64b(b, &k)) return (-1);
if (k64_to_f64(x_out, k)) { b->f |= BF_BROKEN; return (-1); }
return (0);
}
+int (dbuf_getf64)(dbuf *db, double *x_out)
+ { return (dbuf_getf64(db, x_out)); }
+int (dbuf_getf64l)(dbuf *db, double *x_out)
+ { return (dbuf_getf64l(db, x_out)); }
+int (dbuf_getf64b)(dbuf *db, double *x_out)
+ { return (dbuf_getf64b(db, x_out)); }
+
+/* --- @buf_putf64{,l,b} --- *
+ *
+ * Arguments: @buf *b@ = a buffer to write to
+ * @double x@ = a number to write
+ *
+ * Returns: Zero on success, @-1@ on failure (and the buffer is broken).
+ *
+ * On C89, this function can't detect negative zero so these
+ * will be silently written as positive zero.
+ *
+ * This function doesn't distinguish NaNs. Any NaN is written
+ * as a quiet NaN with all payload bits zero.
+ *
+ * A finite value with too large a magnitude to be represented
+ * is rounded to the appropriate infinity. Other finite values
+ * are rounded as necessary, in the usual IEEE 754 round-to-
+ * nearest-or-even way.
+ */
+
+int buf_putf64(buf *b, double x)
+ { return (buf_putk64(b, f64_to_k64(x))); }
+int buf_putf64l(buf *b, double x)
+ { return (buf_putk64l(b, f64_to_k64(x))); }
+int buf_putf64b(buf *b, double x)
+ { return (buf_putk64b(b, f64_to_k64(x))); }
+
+int (dbuf_putf64)(dbuf *db, double x)
+ { return (dbuf_putf64(db, x)); }
+int (dbuf_putf64l)(dbuf *db, double x)
+ { return (dbuf_putf64l(db, x)); }
+int (dbuf_putf64b)(dbuf *db, double x)
+ { return (dbuf_putf64b(db, x)); }
+
/*----- That's all, folks -------------------------------------------------*/