X-Git-Url: https://git.distorted.org.uk/~mdw/mLib/blobdiff_plain/67b5031ec6d160b5cae425466a34d1be3b211dd4..adec5584e13c63662fda18915280ec026063b29d:/struct/buf-float.c?ds=inline diff --git a/struct/buf-float.c b/struct/buf-float.c index 88d6c44..1f61c02 100644 --- a/struct/buf-float.c +++ b/struct/buf-float.c @@ -63,6 +63,84 @@ * 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 @@ -153,113 +231,9 @@ static kludge64 f64_to_k64(double x) SET64(k, hi, lo); return (k); } -/* --- @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 @@ -285,21 +259,63 @@ int buf_getf64(buf *b, double *x_out) 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 -------------------------------------------------*/