123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- /* GCC Quad-Precision Math Library
- Copyright (C) 2010, 2011 Free Software Foundation, Inc.
- Written by Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
- This file is part of the libquadmath library.
- Libquadmath is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
- Libquadmath is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
- You should have received a copy of the GNU Library General Public
- License along with libquadmath; see the file COPYING.LIB. If
- not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
- Boston, MA 02110-1301, USA. */
- #ifndef QUADMATH_IMP_H
- #define QUADMATH_IMP_H
- #include <errno.h>
- #include <limits.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include "quadmath.h"
- #include "config.h"
- #ifdef HAVE_FENV_H
- # include <fenv.h>
- #endif
- /* Under IEEE 754, an architecture may determine tininess of
- floating-point results either "before rounding" or "after
- rounding", but must do so in the same way for all operations
- returning binary results. Define TININESS_AFTER_ROUNDING to 1 for
- "after rounding" architectures, 0 for "before rounding"
- architectures. */
- #define TININESS_AFTER_ROUNDING 1
- #define HIGH_ORDER_BIT_IS_SET_FOR_SNAN 0
- #define FIX_FLT128_LONG_CONVERT_OVERFLOW 0
- #define FIX_FLT128_LLONG_CONVERT_OVERFLOW 0
- /* Prototypes for internal functions. */
- extern int32_t __quadmath_rem_pio2q (__float128, __float128 *);
- extern void __quadmath_kernel_sincosq (__float128, __float128, __float128 *,
- __float128 *, int);
- extern __float128 __quadmath_kernel_sinq (__float128, __float128, int);
- extern __float128 __quadmath_kernel_cosq (__float128, __float128);
- extern __float128 __quadmath_kernel_tanq (__float128, __float128, int);
- extern __float128 __quadmath_gamma_productq (__float128, __float128, int,
- __float128 *);
- extern __float128 __quadmath_gammaq_r (__float128, int *);
- extern __float128 __quadmath_lgamma_negq (__float128, int *);
- extern __float128 __quadmath_lgamma_productq (__float128, __float128,
- __float128, int);
- extern __float128 __quadmath_lgammaq_r (__float128, int *);
- extern __float128 __quadmath_x2y2m1q (__float128 x, __float128 y);
- extern __complex128 __quadmath_kernel_casinhq (__complex128, int);
- static inline void
- mul_splitq (__float128 *hi, __float128 *lo, __float128 x, __float128 y)
- {
- /* Fast built-in fused multiply-add. */
- *hi = x * y;
- *lo = fmaq (x, y, -*hi);
- }
- /* Frankly, if you have __float128, you have 64-bit integers, right? */
- #ifndef UINT64_C
- # error "No way!"
- #endif
- /* Main union type we use to manipulate the floating-point type. */
- typedef union
- {
- __float128 value;
- struct
- #ifdef __MINGW32__
- /* On mingw targets the ms-bitfields option is active by default.
- Therefore enforce gnu-bitfield style. */
- __attribute__ ((gcc_struct))
- #endif
- {
- #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- unsigned negative:1;
- unsigned exponent:15;
- unsigned mantissa0:16;
- unsigned mantissa1:32;
- unsigned mantissa2:32;
- unsigned mantissa3:32;
- #else
- unsigned mantissa3:32;
- unsigned mantissa2:32;
- unsigned mantissa1:32;
- unsigned mantissa0:16;
- unsigned exponent:15;
- unsigned negative:1;
- #endif
- } ieee;
- struct
- {
- #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- uint64_t high;
- uint64_t low;
- #else
- uint64_t low;
- uint64_t high;
- #endif
- } words64;
- struct
- {
- #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- uint32_t w0;
- uint32_t w1;
- uint32_t w2;
- uint32_t w3;
- #else
- uint32_t w3;
- uint32_t w2;
- uint32_t w1;
- uint32_t w0;
- #endif
- } words32;
- struct
- #ifdef __MINGW32__
- /* Make sure we are using gnu-style bitfield handling. */
- __attribute__ ((gcc_struct))
- #endif
- {
- #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
- unsigned negative:1;
- unsigned exponent:15;
- unsigned quiet_nan:1;
- unsigned mantissa0:15;
- unsigned mantissa1:32;
- unsigned mantissa2:32;
- unsigned mantissa3:32;
- #else
- unsigned mantissa3:32;
- unsigned mantissa2:32;
- unsigned mantissa1:32;
- unsigned mantissa0:15;
- unsigned quiet_nan:1;
- unsigned exponent:15;
- unsigned negative:1;
- #endif
- } ieee_nan;
- } ieee854_float128;
- /* Get two 64 bit ints from a long double. */
- #define GET_FLT128_WORDS64(ix0,ix1,d) \
- do { \
- ieee854_float128 u; \
- u.value = (d); \
- (ix0) = u.words64.high; \
- (ix1) = u.words64.low; \
- } while (0)
- /* Set a long double from two 64 bit ints. */
- #define SET_FLT128_WORDS64(d,ix0,ix1) \
- do { \
- ieee854_float128 u; \
- u.words64.high = (ix0); \
- u.words64.low = (ix1); \
- (d) = u.value; \
- } while (0)
- /* Get the more significant 64 bits of a long double mantissa. */
- #define GET_FLT128_MSW64(v,d) \
- do { \
- ieee854_float128 u; \
- u.value = (d); \
- (v) = u.words64.high; \
- } while (0)
- /* Set the more significant 64 bits of a long double mantissa from an int. */
- #define SET_FLT128_MSW64(d,v) \
- do { \
- ieee854_float128 u; \
- u.value = (d); \
- u.words64.high = (v); \
- (d) = u.value; \
- } while (0)
- /* Get the least significant 64 bits of a long double mantissa. */
- #define GET_FLT128_LSW64(v,d) \
- do { \
- ieee854_float128 u; \
- u.value = (d); \
- (v) = u.words64.low; \
- } while (0)
- #define IEEE854_FLOAT128_BIAS 0x3fff
- #define QUADFP_NAN 0
- #define QUADFP_INFINITE 1
- #define QUADFP_ZERO 2
- #define QUADFP_SUBNORMAL 3
- #define QUADFP_NORMAL 4
- #define fpclassifyq(x) \
- __builtin_fpclassify (QUADFP_NAN, QUADFP_INFINITE, QUADFP_NORMAL, \
- QUADFP_SUBNORMAL, QUADFP_ZERO, x)
- #ifndef math_opt_barrier
- # define math_opt_barrier(x) \
- ({ __typeof (x) __x = (x); __asm ("" : "+m" (__x)); __x; })
- # define math_force_eval(x) \
- ({ __typeof (x) __x = (x); __asm __volatile__ ("" : : "m" (__x)); })
- #endif
- /* math_narrow_eval reduces its floating-point argument to the range
- and precision of its semantic type. (The original evaluation may
- still occur with excess range and precision, so the result may be
- affected by double rounding.) */
- #define math_narrow_eval(x) (x)
- /* If X (which is not a NaN) is subnormal, force an underflow
- exception. */
- #define math_check_force_underflow(x) \
- do \
- { \
- __float128 force_underflow_tmp = (x); \
- if (fabsq (force_underflow_tmp) < FLT128_MIN) \
- { \
- __float128 force_underflow_tmp2 \
- = force_underflow_tmp * force_underflow_tmp; \
- math_force_eval (force_underflow_tmp2); \
- } \
- } \
- while (0)
- /* Likewise, but X is also known to be nonnegative. */
- #define math_check_force_underflow_nonneg(x) \
- do \
- { \
- __float128 force_underflow_tmp = (x); \
- if (force_underflow_tmp < FLT128_MIN) \
- { \
- __float128 force_underflow_tmp2 \
- = force_underflow_tmp * force_underflow_tmp; \
- math_force_eval (force_underflow_tmp2); \
- } \
- } \
- while (0)
- /* Likewise, for both real and imaginary parts of a complex
- result. */
- #define math_check_force_underflow_complex(x) \
- do \
- { \
- __typeof (x) force_underflow_complex_tmp = (x); \
- math_check_force_underflow (__real__ force_underflow_complex_tmp); \
- math_check_force_underflow (__imag__ force_underflow_complex_tmp); \
- } \
- while (0)
- #ifndef HAVE_FENV_H
- # define feraiseexcept(arg) ((void) 0)
- typedef int fenv_t;
- # define feholdexcept(arg) ((void) 0)
- # define fesetround(arg) ((void) 0)
- # define feupdateenv(arg) ((void) (arg))
- # define fesetenv(arg) ((void) (arg))
- # define fetestexcept(arg) 0
- # define feclearexcept(arg) ((void) 0)
- #else
- # ifndef HAVE_FEHOLDEXCEPT
- # define feholdexcept(arg) ((void) 0)
- # endif
- # ifndef HAVE_FESETROUND
- # define fesetround(arg) ((void) 0)
- # endif
- # ifndef HAVE_FEUPDATEENV
- # define feupdateenv(arg) ((void) (arg))
- # endif
- # ifndef HAVE_FESETENV
- # define fesetenv(arg) ((void) (arg))
- # endif
- # ifndef HAVE_FETESTEXCEPT
- # define fetestexcept(arg) 0
- # endif
- #endif
- #ifndef __glibc_likely
- # define __glibc_likely(cond) __builtin_expect ((cond), 1)
- #endif
- #ifndef __glibc_unlikely
- # define __glibc_unlikely(cond) __builtin_expect ((cond), 0)
- #endif
- #if defined HAVE_FENV_H && defined HAVE_FESETROUND && defined HAVE_FEUPDATEENV
- struct rm_ctx
- {
- fenv_t env;
- bool updated_status;
- };
- # define SET_RESTORE_ROUNDF128(RM) \
- struct rm_ctx ctx __attribute__((cleanup (libc_feresetround_ctx))); \
- libc_feholdsetround_ctx (&ctx, (RM))
- static inline __attribute__ ((always_inline)) void
- libc_feholdsetround_ctx (struct rm_ctx *ctx, int round)
- {
- ctx->updated_status = false;
- /* Update rounding mode only if different. */
- if (__glibc_unlikely (round != fegetround ()))
- {
- ctx->updated_status = true;
- fegetenv (&ctx->env);
- fesetround (round);
- }
- }
- static inline __attribute__ ((always_inline)) void
- libc_feresetround_ctx (struct rm_ctx *ctx)
- {
- /* Restore the rounding mode if updated. */
- if (__glibc_unlikely (ctx->updated_status))
- feupdateenv (&ctx->env);
- }
- #else
- # define SET_RESTORE_ROUNDF128(RM) ((void) 0)
- #endif
- #endif
|