149 lines
4.3 KiB
C
149 lines
4.3 KiB
C
/*
|
|
* ====================================================
|
|
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
|
*
|
|
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
|
* Permission to use, copy, modify, and distribute this
|
|
* software is freely granted, provided that this notice
|
|
* is preserved.
|
|
* ====================================================
|
|
*/
|
|
|
|
#include <inttypes.h>
|
|
#include <float.h>
|
|
|
|
typedef unsigned int u_int32_t;
|
|
|
|
typedef union
|
|
{
|
|
double value;
|
|
struct
|
|
{
|
|
u_int32_t lsw;
|
|
u_int32_t msw;
|
|
} parts;
|
|
} ieee_double_shape_type;
|
|
|
|
typedef union {
|
|
float value;
|
|
u_int32_t word;
|
|
} ieee_float_shape_type;
|
|
|
|
/* Get two 32 bit ints from a double. */
|
|
|
|
#define EXTRACT_WORDS(ix0,ix1,d) \
|
|
do { \
|
|
ieee_double_shape_type ew_u; \
|
|
ew_u.value = (d); \
|
|
(ix0) = ew_u.parts.msw; \
|
|
(ix1) = ew_u.parts.lsw; \
|
|
} while (0)
|
|
|
|
/* Get the most significant 32 bit int from a double. */
|
|
|
|
#define GET_HIGH_WORD(i,d) \
|
|
do { \
|
|
ieee_double_shape_type gh_u; \
|
|
gh_u.value = (d); \
|
|
(i) = gh_u.parts.msw; \
|
|
} while (0)
|
|
|
|
/* Get the less significant 32 bit int from a double. */
|
|
|
|
#define GET_LOW_WORD(i,d) \
|
|
do { \
|
|
ieee_double_shape_type gl_u; \
|
|
gl_u.value = (d); \
|
|
(i) = gl_u.parts.lsw; \
|
|
} while (0)
|
|
|
|
/* Set a double from two 32 bit ints. */
|
|
|
|
#define INSERT_WORDS(d,ix0,ix1) \
|
|
do { \
|
|
ieee_double_shape_type iw_u; \
|
|
iw_u.parts.msw = (ix0); \
|
|
iw_u.parts.lsw = (ix1); \
|
|
(d) = iw_u.value; \
|
|
} while (0)
|
|
|
|
/* Set the more significant 32 bits of a double from an int. */
|
|
|
|
#define SET_HIGH_WORD(d,v) \
|
|
do { \
|
|
ieee_double_shape_type sh_u; \
|
|
sh_u.value = (d); \
|
|
sh_u.parts.msw = (v); \
|
|
(d) = sh_u.value; \
|
|
} while (0)
|
|
|
|
/* Set the less significant 32 bits of a double from an int. */
|
|
|
|
#define SET_LOW_WORD(d,v) \
|
|
do { \
|
|
ieee_double_shape_type sl_u; \
|
|
sl_u.value = (d); \
|
|
sl_u.parts.lsw = (v); \
|
|
(d) = sl_u.value; \
|
|
} while (0)
|
|
|
|
#define GET_FLOAT_WORD(i,d) do \
|
|
{ \
|
|
ieee_float_shape_type gf_u; \
|
|
gf_u.value = (d); \
|
|
(i) = gf_u.word; \
|
|
} while(0)
|
|
|
|
#define SET_FLOAT_WORD(d,i) do \
|
|
{ \
|
|
ieee_float_shape_type gf_u; \
|
|
gf_u.word = (i); \
|
|
(d) = gf_u.value; \
|
|
} while(0)
|
|
|
|
|
|
#ifdef FLT_EVAL_METHOD
|
|
/*
|
|
* Attempt to get strict C99 semantics for assignment with non-C99 compilers.
|
|
*/
|
|
#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0
|
|
#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
|
|
#else
|
|
#define STRICT_ASSIGN(type, lval, rval) do { \
|
|
volatile type __lval; \
|
|
\
|
|
if (sizeof(type) >= sizeof(long double)) \
|
|
(lval) = (rval); \
|
|
else { \
|
|
__lval = (rval); \
|
|
(lval) = __lval; \
|
|
} \
|
|
} while (0)
|
|
#endif
|
|
#endif /* FLT_EVAL_METHOD */
|
|
|
|
/*
|
|
* Mix 0, 1 or 2 NaNs. First add 0 to each arg. This normally just turns
|
|
* signaling NaNs into quiet NaNs by setting a quiet bit. We do this
|
|
* because we want to never return a signaling NaN, and also because we
|
|
* don't want the quiet bit to affect the result. Then mix the converted
|
|
* args using the specified operation.
|
|
*
|
|
* When one arg is NaN, the result is typically that arg quieted. When both
|
|
* args are NaNs, the result is typically the quietening of the arg whose
|
|
* mantissa is largest after quietening. When neither arg is NaN, the
|
|
* result may be NaN because it is indeterminate, or finite for subsequent
|
|
* construction of a NaN as the indeterminate 0.0L/0.0L.
|
|
*
|
|
* Technical complications: the result in bits after rounding to the final
|
|
* precision might depend on the runtime precision and/or on compiler
|
|
* optimizations, especially when different register sets are used for
|
|
* different precisions. Try to make the result not depend on at least the
|
|
* runtime precision by always doing the main mixing step in long double
|
|
* precision. Try to reduce dependencies on optimizations by adding the
|
|
* the 0's in different precisions (unless everything is in long double
|
|
* precision).
|
|
*/
|
|
#define nan_mix(x, y) (nan_mix_op((x), (y), +))
|
|
#define nan_mix_op(x, y, op) (((x) + 0.0L) op ((y) + 0))
|