diff options
-rw-r--r-- | ext/fputils/Makefile.am | 8 | ||||
-rw-r--r-- | ext/fputils/SConscript | 1 | ||||
-rw-r--r-- | ext/fputils/configure.ac (renamed from ext/fputils/configure.in) | 2 | ||||
-rw-r--r-- | ext/fputils/fp64.c | 45 | ||||
-rw-r--r-- | ext/fputils/fp80.c | 56 | ||||
-rw-r--r-- | ext/fputils/fpbits.h | 17 | ||||
-rw-r--r-- | ext/fputils/include/fputils/fp64.h | 73 | ||||
-rw-r--r-- | ext/fputils/include/fputils/fp80.h | 60 | ||||
-rw-r--r-- | ext/fputils/include/fputils/fptypes.h | 86 |
9 files changed, 292 insertions, 56 deletions
diff --git a/ext/fputils/Makefile.am b/ext/fputils/Makefile.am index d635d0e36..c8aaac410 100644 --- a/ext/fputils/Makefile.am +++ b/ext/fputils/Makefile.am @@ -6,11 +6,17 @@ MOSTLYCLEANFILES= lib_LTLIBRARIES = libfputils.la -include_HEADERS = include/fputils/fp80.h +include_HEADERS = \ + include/fputils/fp80.h \ + include/fputils/fp64.h \ + include/fputils/fptypes.h libfputils_la_SOURCES = \ include/fputils/fp80.h \ + include/fputils/fp64.h \ + include/fputils/fptypes.h \ fpbits.h \ + fp64.c \ fp80.c diff --git a/ext/fputils/SConscript b/ext/fputils/SConscript index 9c5685264..6d3f1ff8d 100644 --- a/ext/fputils/SConscript +++ b/ext/fputils/SConscript @@ -40,6 +40,7 @@ if fpenv['GCC']: fpenv.Append(CCFLAGS=['-std=c99']) fpenv.Library('fputils', [ + fpenv.SharedObject('fp64.c'), fpenv.SharedObject('fp80.c'), ]) diff --git a/ext/fputils/configure.in b/ext/fputils/configure.ac index bb2291b6f..35cade885 100644 --- a/ext/fputils/configure.in +++ b/ext/fputils/configure.ac @@ -2,7 +2,7 @@ AC_INIT(libfputils, 1.0, andreas@sandberg.pp.se) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([foreign -Wall -Werror]) +AM_INIT_AUTOMAKE([foreign -Wall]) DX_PDF_FEATURE(OFF) DX_PS_FEATURE(OFF) diff --git a/ext/fputils/fp64.c b/ext/fputils/fp64.c new file mode 100644 index 000000000..eb2ebc9ad --- /dev/null +++ b/ext/fputils/fp64.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, Andreas Sandberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <fputils/fp64.h> +#include "fpbits.h" + +#include <assert.h> +#include <stdint.h> + +#include <stdio.h> + +const fp64_t fp64_pinf = BUILD_FP64(0, 0, FP64_EXP_SPECIAL); +const fp64_t fp64_ninf = BUILD_FP64(1, 0, FP64_EXP_SPECIAL); +const fp64_t fp64_qnan = BUILD_FP64(0, FP64_FRAC_QNAN, FP64_EXP_SPECIAL); +const fp64_t fp64_nqnan = BUILD_FP64(1, FP64_FRAC_QNAN, FP64_EXP_SPECIAL); +const fp64_t fp64_qnani = BUILD_FP64(1, FP64_FRAC_QNANI, FP64_EXP_SPECIAL); +const fp64_t fp64_snan = BUILD_FP64(0, FP64_FRAC_SNAN, FP64_EXP_SPECIAL); +const fp64_t fp64_nsnan = BUILD_FP64(1, FP64_FRAC_SNAN, FP64_EXP_SPECIAL); +const fp64_t fp64_nan = BUILD_FP64(0, FP64_FRAC_QNAN, FP64_EXP_SPECIAL); diff --git a/ext/fputils/fp80.c b/ext/fputils/fp80.c index 8100a4d99..aaa4ee5a0 100644 --- a/ext/fputils/fp80.c +++ b/ext/fputils/fp80.c @@ -28,6 +28,7 @@ */ #include <fputils/fp80.h> +#include <fputils/fp64.h> #include "fpbits.h" #include <assert.h> @@ -35,39 +36,13 @@ #include <stdio.h> -typedef union { - uint64_t bits; - double value; -} fp64_t; - -const fp80_t fp80_pinf = BUILD_FP80(0, 0, FP80_EXP_SPECIAL); -const fp80_t fp80_ninf = BUILD_FP80(1, 0, FP80_EXP_SPECIAL); -const fp80_t fp80_qnan = BUILD_FP80(0, FP80_FRAC_QNAN, FP80_EXP_SPECIAL); +const fp80_t fp80_pinf = BUILD_FP80(0, 0, FP80_EXP_SPECIAL); +const fp80_t fp80_ninf = BUILD_FP80(1, 0, FP80_EXP_SPECIAL); +const fp80_t fp80_qnan = BUILD_FP80(0, FP80_FRAC_QNAN, FP80_EXP_SPECIAL); const fp80_t fp80_qnani = BUILD_FP80(1, FP80_FRAC_QNANI, FP80_EXP_SPECIAL); -const fp80_t fp80_snan = BUILD_FP80(0, FP80_FRAC_SNAN, FP80_EXP_SPECIAL); -const fp80_t fp80_nan = BUILD_FP80(0, FP80_FRAC_QNAN, FP80_EXP_SPECIAL); - -static const fp64_t fp64_pinf = BUILD_FP64(0, 0, FP64_EXP_SPECIAL); -static const fp64_t fp64_ninf = BUILD_FP64(1, 0, FP64_EXP_SPECIAL); -static const fp64_t fp64_qnan = BUILD_FP64(0, FP64_FRAC_QNAN, - FP64_EXP_SPECIAL); -static const fp64_t fp64_nqnan = BUILD_FP64(1, FP64_FRAC_QNAN, - FP64_EXP_SPECIAL); -static const fp64_t fp64_qnani = BUILD_FP64(1, FP64_FRAC_QNANI, - FP64_EXP_SPECIAL); -static const fp64_t fp64_snan = BUILD_FP64(0, FP64_FRAC_SNAN, - FP64_EXP_SPECIAL); -static const fp64_t fp64_nsnan = BUILD_FP64(1, FP64_FRAC_SNAN, - FP64_EXP_SPECIAL); - -static double -build_fp64(int sign, uint64_t frac, int exp) -{ - const fp64_t f = BUILD_FP64(sign, frac, exp); - - return f.value; -} +const fp80_t fp80_snan = BUILD_FP80(0, FP80_FRAC_SNAN, FP80_EXP_SPECIAL); +const fp80_t fp80_nan = BUILD_FP80(0, FP80_FRAC_QNAN, FP80_EXP_SPECIAL); int fp80_sgn(fp80_t fp80) @@ -167,6 +142,12 @@ fp80_classify(fp80_t fp80) double fp80_cvtd(fp80_t fp80) { + return fp80_cvtfp64(fp80).value; +} + +fp64_t +fp80_cvtfp64(fp80_t fp80) +{ const int sign = fp80.repr.se & FP80_SIGN_BIT; if (!fp80_isspecial(fp80)) { @@ -191,12 +172,12 @@ fp80_cvtd(fp80_t fp80) if (fp80_isinf(fp80)) { return build_fp64(sign, 0, FP64_EXP_SPECIAL); } else if (fp80_issnan(fp80)) { - return fp80_sgn(fp80) > 0 ? fp64_snan.value : fp64_nsnan.value; + return fp80_sgn(fp80) > 0 ? fp64_snan : fp64_nsnan; } else if (fp80_isqnani(fp80)) { - return fp64_qnani.value; + return fp64_qnani; } else { assert(fp80_isqnan(fp80)); - return fp80_sgn(fp80) > 0 ? fp64_qnan.value : fp64_nqnan.value; + return fp80_sgn(fp80) > 0 ? fp64_qnan : fp64_nqnan; } } } @@ -205,6 +186,13 @@ fp80_t fp80_cvfd(double value) { const fp64_t fp64 = { .value = value }; + + return fp80_cvffp64(fp64); +} + +fp80_t +fp80_cvffp64(fp64_t fp64) +{ const uint64_t frac = FP64_FRAC(fp64); const unsigned exp = FP64_EXP(fp64); const int unb_exp = exp - FP64_EXP_BIAS; diff --git a/ext/fputils/fpbits.h b/ext/fputils/fpbits.h index 335a122d3..f85a3b2f0 100644 --- a/ext/fputils/fpbits.h +++ b/ext/fputils/fpbits.h @@ -66,6 +66,14 @@ #define BUILD_FP64(sign, frac, exp) \ { .bits = BUILD_IFP64(sign, frac, exp) } +static inline fp64_t +build_fp64(int sign, uint64_t frac, int exp) +{ + const fp64_t f = BUILD_FP64(sign, frac, exp); + + return f; +} + #define BUILD_FP80_SE(sign, exp) \ ((sign) ? FP80_SIGN_BIT : 0) | \ ((exp) & FP80_EXP_MASK) @@ -80,6 +88,14 @@ .repr.fi = BUILD_FP80_FI(frac, exp) \ } +static inline fp80_t +build_fp80(int sign, uint64_t frac, int exp) +{ + const fp80_t f = BUILD_FP80(sign, frac, exp); + + return f; +} + #define FP80_FRAC(fp80) \ (fp80.repr.fi & FP80_FRAC_MASK) @@ -92,4 +108,5 @@ #define FP64_EXP(fp80) \ ((fp64.bits & FP64_EXP_MASK) >> FP64_EXP_SHIFT) + #endif diff --git a/ext/fputils/include/fputils/fp64.h b/ext/fputils/include/fputils/fp64.h new file mode 100644 index 000000000..91ebf6b12 --- /dev/null +++ b/ext/fputils/include/fputils/fp64.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, Andreas Sandberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FP64_H +#define _FP64_H 1 + +#include <fputils/fptypes.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @defgroup fp64 64-bit Floats + * Functions handling 64-bit floats. + * + * @{ + */ + + +/** Constant representing +inf */ +extern const fp64_t fp64_pinf; +/** Constant representing -inf */ +extern const fp64_t fp64_ninf; + +/** Constant representing a quiet NaN */ +extern const fp64_t fp64_qnan; +/** Constant representing a negative quiet NaN */ +extern const fp64_t fp64_nqnan; +/** Constant representing a quiet indefinite NaN */ +extern const fp64_t fp64_qnani; +/** Constant representing a signaling NaN */ +extern const fp64_t fp64_snan; +/** Constant representing a negative signaling NaN */ +extern const fp64_t fp64_nsnan; + +/** Alias for fp64_qnan */ +extern const fp64_t fp64_nan; + +/** @} */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/ext/fputils/include/fputils/fp80.h b/ext/fputils/include/fputils/fp80.h index 70acb6cb1..c824baa1c 100644 --- a/ext/fputils/include/fputils/fp80.h +++ b/ext/fputils/include/fputils/fp80.h @@ -30,10 +30,12 @@ #ifndef _FP80_H #define _FP80_H 1 -#include <math.h> -#include <stdint.h> +#include <math.h> /* FP_NAN et al. */ #include <stdio.h> +#include <fputils/fptypes.h> + + #ifdef __cplusplus extern "C" { #endif @@ -45,15 +47,6 @@ extern "C" { * @{ */ -/** Internal representation of an 80-bit float. */ -typedef union { - char bits[10]; - struct { - uint64_t fi; - uint16_t se; - } repr; -} fp80_t; - /** Constant representing +inf */ extern const fp80_t fp80_pinf; /** Constant representing -inf */ @@ -190,6 +183,21 @@ int fp80_iszero(fp80_t fp80); */ int fp80_issubnormal(fp80_t fp80); + +/** + * Convert an 80-bit float to a 64-bit double. + * + * Convenience wrapper around fp80_cvtfp64() that returns a double + * instead of the internal fp64_t representation. + * + * Note that this conversion is lossy, see fp80_cvtfp64() for details + * of the conversion. + * + * @param fp80 Source value to convert. + * @return value represented as double. + */ +double fp80_cvtd(fp80_t fp80); + /** * Convert an 80-bit float to a 64-bit double. * @@ -214,24 +222,36 @@ int fp80_issubnormal(fp80_t fp80); * @param fp80 Source value to convert. * @return 64-bit version of the float. */ -double fp80_cvtd(fp80_t fp80); +fp64_t fp80_cvtfp64(fp80_t fp80); /** - * Convert an 64-bit double to an 80-bit float. - * - * This function converts a standard 64-bit double into an 80-bit - * float. This conversion is completely lossless since the 80-bit - * float represents a superset of what a 64-bit double can - * represent. + * Convert a double to an 80-bit float. * - * @note Denormals will be converted to normalized values. + * This is a convenience wrapper around fp80_cvffp64() and provides a + * convenient way of using the native double type instead of the + * internal fp64_t representation. * * @param fpd Source value to convert. - * @return 64-bit version of the float. + * @return 80-bit version of the float. */ fp80_t fp80_cvfd(double fpd); /** + * Convert a 64-bit float to an 80-bit float. + * + * This function converts the internal representation of a 64-bit + * float into an 80-bit float. This conversion is completely lossless + * since the 80-bit float represents a superset of what a 64-bit + * float can represent. + * + * @note Denormals will be converted to normalized values. + * + * @param fp64 64-bit float to convert. + * @return 80-bit version of the float. + */ +fp80_t fp80_cvffp64(fp64_t fp64); + +/** * Dump the components of an 80-bit float to a file. * * @warning This function is intended for debugging and the format of diff --git a/ext/fputils/include/fputils/fptypes.h b/ext/fputils/include/fputils/fptypes.h new file mode 100644 index 000000000..714ddd439 --- /dev/null +++ b/ext/fputils/include/fputils/fptypes.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014, Andreas Sandberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FPTYPES_H +#define _FPTYPES_H 1 + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup fp64 + * @{ + */ + +/** Internal representation of a 64-bit float */ +typedef union { + /** + * Raw value exposed as an unsigned integer. Mainly used for bit + * manipulation. + */ + uint64_t bits; + /** Representation using the built-in double type */ + double value; +} fp64_t; + +/** @} */ + + +/** + * @addtogroup fp80 + * @{ + */ + +/** Internal representation of an 80-bit float. */ +typedef union { + struct { + /** Raw representation of the integer part bit and the + * fraction. Note that unlike 64-bit floating point + * representations the integer bit is explicit. */ + uint64_t fi; + /** Raw representation of sign bit and exponent */ + uint16_t se; + } repr; + /** + * Represented as a char array, mainly intended for debug dumping + * and serialization. + */ + char bits[10]; +} fp80_t; + +/** @} */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif |