mirror of
https://github.com/phabrics/Run-Sun3-SunOS-4.1.1.git
synced 2026-04-29 19:12:58 -04:00
499 lines
22 KiB
C
499 lines
22 KiB
C
/* $Id: float.h,v 1.5 2009/08/29 21:19:43 fredette Exp $ */
|
|
|
|
/* tme/generic/float.h - public header file for floating-point emulation */
|
|
|
|
/*
|
|
* Copyright (c) 2004 Matt Fredette
|
|
* 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.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Matt Fredette.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 _TME_GENERIC_FLOAT_H
|
|
#define _TME_GENERIC_FLOAT_H
|
|
|
|
#include <tme/common.h>
|
|
_TME_RCSID("$Id: float.h,v 1.5 2009/08/29 21:19:43 fredette Exp $");
|
|
|
|
/* includes: */
|
|
#include <tme/threads.h>
|
|
#include <setjmp.h>
|
|
#include <math.h>
|
|
#ifdef _TME_HAVE_IEEEFP_H
|
|
#include <ieeefp.h>
|
|
#endif /* _TME_HAVE_IEEEFP_H */
|
|
#ifdef _TME_HAVE_FLOAT_H
|
|
#include <float.h>
|
|
#endif /* _TME_HAVE_FLOAT_H */
|
|
#ifdef _TME_HAVE_LIMITS_H
|
|
#include <limits.h>
|
|
#endif /* _TME_HAVE_LIMITS_H */
|
|
|
|
/* macros: */
|
|
|
|
/* floating-point formats. even though these are individual bits, we
|
|
can't use TME_BIT() because these are used in preprocessor ifs: */
|
|
#define TME_FLOAT_FORMAT_NULL (0)
|
|
#ifndef TME_FLOAT_FORMAT_FLOAT
|
|
#define TME_FLOAT_FORMAT_FLOAT (1)
|
|
#endif /* !TME_FLOAT_FORMAT_FLOAT */
|
|
#ifndef TME_FLOAT_FORMAT_DOUBLE
|
|
#define TME_FLOAT_FORMAT_DOUBLE (2)
|
|
#endif /* !TME_FLOAT_FORMAT_FLOAT */
|
|
#ifdef _TME_HAVE_LONG_DOUBLE
|
|
#ifndef TME_FLOAT_FORMAT_LONG_DOUBLE
|
|
#define TME_FLOAT_FORMAT_LONG_DOUBLE (4)
|
|
#endif /* !TME_FLOAT_FORMAT_LONG_DOUBLE */
|
|
#endif /* _TME_HAVE_LONG_DOUBLE */
|
|
#define TME_FLOAT_FORMAT_IEEE754_SINGLE (8)
|
|
#define TME_FLOAT_FORMAT_IEEE754_DOUBLE (16)
|
|
#define TME_FLOAT_FORMAT_IEEE754_EXTENDED80_I387 (32)
|
|
#define TME_FLOAT_FORMAT_IEEE754_EXTENDED80_M68881 (64)
|
|
#define TME_FLOAT_FORMAT_IEEE754_QUAD (128)
|
|
|
|
/* if the long double type is available, this expands to the code
|
|
fragment in x, else it expands to nothing: */
|
|
#ifdef _TME_HAVE_LONG_DOUBLE
|
|
#define TME_FLOAT_IF_LONG_DOUBLE(x) x
|
|
#else /* !_TME_HAVE_LONG_DOUBLE */
|
|
#define TME_FLOAT_IF_LONG_DOUBLE(x) /* */
|
|
#endif /* !_TME_HAVE_LONG_DOUBLE */
|
|
|
|
/* a mask of all builtin floating-point formats: */
|
|
#define TME_FLOAT_FORMATS_BUILTIN (TME_FLOAT_FORMAT_FLOAT \
|
|
| TME_FLOAT_FORMAT_DOUBLE \
|
|
TME_FLOAT_IF_LONG_DOUBLE(| TME_FLOAT_FORMAT_LONG_DOUBLE))
|
|
|
|
/* floating-point rounding modes: */
|
|
#ifdef _TME_HAVE_FPSETROUND
|
|
#define TME_FLOAT_ROUND_NULL (0xdeadbeef)
|
|
#define TME_FLOAT_ROUND_NEAREST_EVEN (FP_RN)
|
|
#define TME_FLOAT_ROUND_DOWN (FP_RM)
|
|
#define TME_FLOAT_ROUND_UP (FP_RP)
|
|
#define TME_FLOAT_ROUND_TO_ZERO (FP_RZ)
|
|
#else /* !_TME_HAVE_FPSETROUND */
|
|
#define TME_FLOAT_ROUND_NULL (0)
|
|
#define TME_FLOAT_ROUND_NEAREST_EVEN (1)
|
|
#define TME_FLOAT_ROUND_DOWN (2)
|
|
#define TME_FLOAT_ROUND_UP (3)
|
|
#define TME_FLOAT_ROUND_TO_ZERO (4)
|
|
#endif /* !_TME_HAVE_FPSETROUND */
|
|
|
|
/* floating-point exceptions: */
|
|
#define TME_FLOAT_EXCEPTION_GENERIC TME_BIT(0)
|
|
#define TME_FLOAT_EXCEPTION_INVALID TME_BIT(1)
|
|
#define TME_FLOAT_EXCEPTION_DIVBYZERO TME_BIT(2)
|
|
#define TME_FLOAT_EXCEPTION_OVERFLOW TME_BIT(3)
|
|
#define TME_FLOAT_EXCEPTION_UNDERFLOW TME_BIT(4)
|
|
#define TME_FLOAT_EXCEPTION_INEXACT TME_BIT(5)
|
|
#define TME_FLOAT_EXCEPTION_OVERFLOW_INT TME_BIT(6)
|
|
#define TME_FLOAT_EXCEPTION_DENORMAL TME_BIT(7)
|
|
|
|
/* types: */
|
|
|
|
/* each of these types describes a floating point format supported on
|
|
hosts. each of these types may also be used in code that emulates
|
|
the a floating point format, but each type's first purpose is to
|
|
overlap exactly with one or more of the host's builtin C types that
|
|
uses the format.
|
|
|
|
for example, if the host has a builtin C type that uses the i387
|
|
style of the IEEE 754 80-bit extended precision format, struct
|
|
tme_float_ieee754_extended80 matches that style, not the m68k
|
|
style. if no builtin C type uses any style of the IEEE 754 80-bit
|
|
extended precision format, struct tme_float_ieee754_extended80
|
|
matches a random style.
|
|
|
|
member values in these structures are always in host byte and word
|
|
order.
|
|
|
|
we also allow for these parts of the header file to be multiply
|
|
included, so that these types can be incorporated into emulation
|
|
code under different names: */
|
|
|
|
/* tme_uint32_t is used for the IEEE 754 single precision format. */
|
|
|
|
/* union tme_value64 is used for the IEEE 754 double precision format. */
|
|
|
|
#undef _TME_GENERIC_FLOAT_H
|
|
#endif /* !_TME_GENERIC_FLOAT_H */
|
|
|
|
#ifndef TME_FLOAT_FORMAT_IEEE754_EXTENDED80
|
|
|
|
/* making the IEEE 754 80-bit extended precision float structure
|
|
overlap with a native type is complicated, since there are four
|
|
possible representations: i387-style (where the 16 bits of sign and
|
|
exponent are adjacent to the significand) and m68881-style (where
|
|
there is a 16-bit gap between the significand and the 16 bits of
|
|
sign and exponent), plus big- and little-endian variants of each: */
|
|
|
|
/* decide where the 16-bit sign-exponent word and any 16-bit padding
|
|
words are in relation to the significand: */
|
|
#if ((TME_FLOAT_FORMATS_BUILTIN & TME_FLOAT_FORMAT_IEEE754_EXTENDED80_M68881) != 0)
|
|
#define TME_FLOAT_FORMAT_IEEE754_EXTENDED80 TME_FLOAT_FORMAT_IEEE754_EXTENDED80_M68881
|
|
#define _tme_float_ieee754_extended80_word_1 tme_float_ieee754_extended80_sexp
|
|
#define _tme_float_ieee754_extended80_word_0 tme_float_ieee754_extended80_pad
|
|
#else /* ((TME_FLOAT_FORMATS_BUILTIN & TME_FLOAT_FORMAT_IEEE754_EXTENDED80_M68881) == 0) */
|
|
#define TME_FLOAT_FORMAT_IEEE754_EXTENDED80 TME_FLOAT_FORMAT_IEEE754_EXTENDED80_I387
|
|
#define _tme_float_ieee754_extended80_word_0 tme_float_ieee754_extended80_sexp
|
|
#endif /* ((TME_FLOAT_FORMATS_BUILTIN & TME_FLOAT_FORMAT_IEEE754_EXTENDED80_M68881) == 0) */
|
|
|
|
/* the IEEE 754 80-bit extended precision format: */
|
|
struct tme_float_ieee754_extended80 {
|
|
|
|
/* if this is a big-endian host: */
|
|
#ifdef _TME_WORDS_BIGENDIAN
|
|
|
|
/* up to four 16-bit words preceding the significand: */
|
|
#ifdef _tme_float_ieee754_extended80_word_3
|
|
tme_uint16_t _tme_float_ieee754_extended80_word_3;
|
|
#endif /* _tme_float_ieee754_extended80_word_3 */
|
|
#ifdef _tme_float_ieee754_extended80_word_2
|
|
tme_uint16_t _tme_float_ieee754_extended80_word_2;
|
|
#endif /* _tme_float_ieee754_extended80_word_2 */
|
|
#ifdef _tme_float_ieee754_extended80_word_1
|
|
tme_uint16_t _tme_float_ieee754_extended80_word_1;
|
|
#endif /* _tme_float_ieee754_extended80_word_1 */
|
|
tme_uint16_t _tme_float_ieee754_extended80_word_0;
|
|
|
|
#endif /* _TME_WORDS_BIGENDIAN */
|
|
|
|
/* the significand: */
|
|
#ifndef tme_float_ieee754_extended80
|
|
union tme_value64 tme_float_ieee754_extended80_significand;
|
|
#else /* !tme_float_ieee754_extended80 */
|
|
tme_uint64_t tme_float_ieee754_extended80_significand;
|
|
#endif /* !tme_float_ieee754_extended80 */
|
|
|
|
/* if this is a little-endian host: */
|
|
#ifndef _TME_WORDS_BIGENDIAN
|
|
|
|
/* up to four 16-bit words following the significand: */
|
|
tme_uint16_t _tme_float_ieee754_extended80_word_0;
|
|
#ifdef _tme_float_ieee754_extended80_word_1
|
|
tme_uint16_t _tme_float_ieee754_extended80_word_1;
|
|
#endif /* _tme_float_ieee754_extended80_word_1 */
|
|
#ifdef _tme_float_ieee754_extended80_word_2
|
|
tme_uint16_t _tme_float_ieee754_extended80_word_2;
|
|
#endif /* _tme_float_ieee754_extended80_word_2 */
|
|
#ifdef _tme_float_ieee754_extended80_word_3
|
|
tme_uint16_t _tme_float_ieee754_extended80_word_3;
|
|
#endif /* _tme_float_ieee754_extended80_word_3 */
|
|
|
|
#endif /* !_TME_WORDS_BIGENDIAN */
|
|
#undef _tme_float_ieee754_extended80_word_0
|
|
#undef _tme_float_ieee754_extended80_word_1
|
|
#undef _tme_float_ieee754_extended80_word_2
|
|
#undef _tme_float_ieee754_extended80_word_3
|
|
};
|
|
|
|
#endif /* TME_FLOAT_FORMAT_IEEE754_EXTENDED80 */
|
|
|
|
#ifndef _TME_GENERIC_FLOAT_H
|
|
#define _TME_GENERIC_FLOAT_H
|
|
|
|
/* the IEEE 754 quad precision format: */
|
|
struct tme_float_ieee754_quad {
|
|
#ifdef _TME_WORDS_BIGENDIAN
|
|
union tme_value64 tme_float_ieee754_quad_hi;
|
|
union tme_value64 tme_float_ieee754_quad_lo;
|
|
#else /* !_TME_WORDS_BIGENDIAN */
|
|
union tme_value64 tme_float_ieee754_quad_lo;
|
|
union tme_value64 tme_float_ieee754_quad_hi;
|
|
#endif /* !_TME_WORDS_BIGENDIAN */
|
|
};
|
|
|
|
/* the generic float: */
|
|
struct tme_float {
|
|
|
|
/* the format of this float: */
|
|
unsigned int tme_float_format;
|
|
|
|
/* the value of this float: */
|
|
union {
|
|
|
|
/* the builtin formats: */
|
|
float _tme_float_union_float;
|
|
double _tme_float_union_double;
|
|
#ifdef _TME_HAVE_LONG_DOUBLE
|
|
long double _tme_float_union_long_double;
|
|
#endif /* _TME_HAVE_LONG_DOUBLE */
|
|
|
|
/* the IEEE 754 formats: */
|
|
tme_uint32_t _tme_float_union_ieee754_single;
|
|
union tme_value64 _tme_float_union_ieee754_double;
|
|
struct tme_float_ieee754_extended80 _tme_float_union_ieee754_extended80;
|
|
struct tme_float_ieee754_quad _tme_float_union_ieee754_quad;
|
|
} _tme_float_union;
|
|
|
|
/* the public member names: */
|
|
#define tme_float_value_float _tme_float_union._tme_float_union_float
|
|
#define tme_float_value_double _tme_float_union._tme_float_union_double
|
|
#ifdef _TME_HAVE_LONG_DOUBLE
|
|
#define tme_float_value_long_double _tme_float_union._tme_float_union_long_double
|
|
#endif /* _TME_HAVE_LONG_DOUBLE */
|
|
#define tme_float_value_ieee754_single _tme_float_union._tme_float_union_ieee754_single
|
|
#define tme_float_value_ieee754_double _tme_float_union._tme_float_union_ieee754_double
|
|
#define tme_float_value_ieee754_extended80 _tme_float_union._tme_float_union_ieee754_extended80
|
|
#define tme_float_value_ieee754_quad _tme_float_union._tme_float_union_ieee754_quad
|
|
};
|
|
|
|
/* prototypes: */
|
|
|
|
/* this enters native floating-point operation: */
|
|
void tme_float_enter _TME_P((int, void (*)(int, void *), void *));
|
|
|
|
/* this returns the current native floating-point exceptions: */
|
|
int tme_float_exceptions _TME_P((void));
|
|
|
|
/* this leaves native floating-point operation: */
|
|
int tme_float_leave _TME_P((void));
|
|
|
|
/* this asserts that the float is in one of the expected formats: */
|
|
#ifndef NDEBUG
|
|
static _tme_inline int
|
|
tme_float_assert_formats(_tme_const struct tme_float *x, unsigned int formats)
|
|
{
|
|
assert (x->tme_float_format & formats);
|
|
return (TRUE);
|
|
}
|
|
#else /* NDEBUG */
|
|
#define tme_float_assert_formats(x, formats) (TRUE)
|
|
#endif /* NDEBUG */
|
|
|
|
/* this evaluates to nonzero if the float is in a certain format, if
|
|
the float is known to be one of the given formats: */
|
|
#define tme_float_is_format(x, formats, format) \
|
|
(((formats) == (format)) || (((formats) & (format)) && ((x)->tme_float_format & (format))))
|
|
|
|
/* this sets a float to a given builtin value: */
|
|
#define tme_float_value_builtin_set(x, format, y) \
|
|
do { \
|
|
if ((format) == TME_FLOAT_FORMAT_FLOAT) { \
|
|
(x)->tme_float_value_float = (y); \
|
|
} \
|
|
TME_FLOAT_IF_LONG_DOUBLE(else if ((format) == TME_FLOAT_FORMAT_LONG_DOUBLE) { \
|
|
(x)->tme_float_value_long_double = (y); \
|
|
}) \
|
|
else { \
|
|
assert((format) == TME_FLOAT_FORMAT_DOUBLE); \
|
|
(x)->tme_float_value_double = (y); \
|
|
} \
|
|
(x)->tme_float_format = (format); \
|
|
} while (/* CONSTCOND */ 0)
|
|
|
|
/* these return the exponents of values in the IEEE 754 formats: */
|
|
#define tme_float_value_ieee754_exponent_single(x) \
|
|
TME_FIELD_MASK_EXTRACTU((x)->tme_float_value_ieee754_single, 0x7f800000)
|
|
#define tme_float_value_ieee754_exponent_double(x) \
|
|
TME_FIELD_MASK_EXTRACTU((x)->tme_float_value_ieee754_double.tme_value64_uint32_hi, 0x7ff00000)
|
|
#define tme_float_value_ieee754_exponent_extended80(x) \
|
|
TME_FIELD_MASK_EXTRACTU((x)->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_sexp, 0x7fff)
|
|
#define tme_float_value_ieee754_exponent_quad(x) \
|
|
TME_FIELD_MASK_EXTRACTU((x)->tme_float_value_ieee754_quad.tme_float_ieee754_quad_hi.tme_value64_uint32_hi, 0x7fff0000)
|
|
|
|
/* these return a bitwise-or of the fraction bits in values in the
|
|
IEEE 754 formats (and, for the IEEE 754 80-bit extended precision
|
|
format, a bitwise-or of the entire significand, including the
|
|
explicit integer bit): */
|
|
#define tme_float_value_ieee754_fracor_single(x) \
|
|
((x)->tme_float_value_ieee754_single & 0x007fffff)
|
|
#define tme_float_value_ieee754_fracor_double(x) \
|
|
(((x)->tme_float_value_ieee754_double.tme_value64_uint32_hi & 0x000fffff) | (x)->tme_float_value_ieee754_double.tme_value64_uint32_lo)
|
|
#define tme_float_value_ieee754_fracor_extended80(x) \
|
|
(((x)->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi << 1) | (x)->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo)
|
|
#define tme_float_value_ieee754_sigor_extended80(x) \
|
|
((x)->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_hi | (x)->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_significand.tme_value64_uint32_lo)
|
|
#define tme_float_value_ieee754_fracor_quad(x) \
|
|
(((x)->tme_float_value_ieee754_quad.tme_float_ieee754_quad_hi.tme_value64_uint32_hi & 0x0000ffff) \
|
|
| (x)->tme_float_value_ieee754_quad.tme_float_ieee754_quad_hi.tme_value64_uint32_lo \
|
|
| (x)->tme_float_value_ieee754_quad.tme_float_ieee754_quad_lo.tme_value64_uint32_hi \
|
|
| (x)->tme_float_value_ieee754_quad.tme_float_ieee754_quad_lo.tme_value64_uint32_lo)
|
|
|
|
/* this evaluates to nonzero if the float is a NaN: */
|
|
#define tme_float_is_nan(x, formats) \
|
|
(tme_float_assert_formats(x, formats) \
|
|
&& (tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_SINGLE) \
|
|
? (tme_float_value_ieee754_exponent_single(x) == 0xff \
|
|
&& tme_float_value_ieee754_fracor_single(x) != 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_DOUBLE) \
|
|
? (tme_float_value_ieee754_exponent_double(x) == 0x7ff \
|
|
&& tme_float_value_ieee754_fracor_double(x) != 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_EXTENDED80) \
|
|
? (tme_float_value_ieee754_exponent_extended80(x) == 0x7fff \
|
|
&& tme_float_value_ieee754_fracor_extended80(x) != 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_QUAD) \
|
|
? (tme_float_value_ieee754_exponent_quad(x) == 0x7fff \
|
|
&& tme_float_value_ieee754_fracor_quad(x) != 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_FLOAT) \
|
|
? isnanf((x)->tme_float_value_float) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_DOUBLE) \
|
|
? isnan((x)->tme_float_value_double) \
|
|
: TME_FLOAT_IF_LONG_DOUBLE(isnan((x)->tme_float_value_long_double) ||) FALSE))
|
|
|
|
/* this evaluates to nonzero if the float is an infinity: */
|
|
#define tme_float_is_inf(x, formats) \
|
|
(tme_float_assert_formats(x, formats) \
|
|
&& (tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_SINGLE) \
|
|
? (tme_float_value_ieee754_exponent_single(x) == 0xff \
|
|
&& tme_float_value_ieee754_fracor_single(x) == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_DOUBLE) \
|
|
? (tme_float_value_ieee754_exponent_double(x) == 0x7ff \
|
|
&& tme_float_value_ieee754_fracor_double(x) == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_EXTENDED80) \
|
|
? (tme_float_value_ieee754_exponent_extended80(x) == 0x7fff \
|
|
&& tme_float_value_ieee754_fracor_extended80(x) == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_QUAD) \
|
|
? (tme_float_value_ieee754_exponent_quad(x) == 0x7fff \
|
|
&& tme_float_value_ieee754_fracor_quad(x) == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_FLOAT) \
|
|
? isinff((x)->tme_float_value_float) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_DOUBLE) \
|
|
? isinf((x)->tme_float_value_double) \
|
|
: TME_FLOAT_IF_LONG_DOUBLE(isinf((x)->tme_float_value_long_double) ||) FALSE))
|
|
|
|
/* this evaluates to nonzero if the float is a zero: */
|
|
#define tme_float_is_zero(x, formats) \
|
|
(tme_float_assert_formats(x, formats) \
|
|
&& (tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_SINGLE) \
|
|
? (tme_float_value_ieee754_exponent_single(x) == 0 \
|
|
&& tme_float_value_ieee754_fracor_single(x) == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_DOUBLE) \
|
|
? (tme_float_value_ieee754_exponent_double(x) == 0 \
|
|
&& tme_float_value_ieee754_fracor_double(x) == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_EXTENDED80) \
|
|
? (tme_float_value_ieee754_exponent_extended80(x) == 0 \
|
|
&& tme_float_value_ieee754_sigor_extended80(x) == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_QUAD) \
|
|
? (tme_float_value_ieee754_exponent_quad(x) == 0 \
|
|
&& tme_float_value_ieee754_fracor_quad(x) == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_FLOAT) \
|
|
? ((x)->tme_float_value_float == 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_DOUBLE) \
|
|
? ((x)->tme_float_value_double == 0) \
|
|
: TME_FLOAT_IF_LONG_DOUBLE(((x)->tme_float_value_long_double == 0) ||) FALSE))
|
|
|
|
/* this evaluates to nonzero if the float is negative: */
|
|
#define tme_float_is_negative(x, formats) \
|
|
(tme_float_assert_formats(x, formats) \
|
|
&& (tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_SINGLE) \
|
|
? (((x)->tme_float_value_ieee754_single & 0x80000000) != 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_DOUBLE) \
|
|
? (((x)->tme_float_value_ieee754_double.tme_value64_uint32_hi & 0x80000000) != 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_EXTENDED80) \
|
|
? (((x)->tme_float_value_ieee754_extended80.tme_float_ieee754_extended80_sexp & 0x8000) != 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_IEEE754_QUAD) \
|
|
? (((x)->tme_float_value_ieee754_quad.tme_float_ieee754_quad_hi.tme_value64_uint32_hi & 0x80000000) != 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_FLOAT) \
|
|
? ((x)->tme_float_value_float < 0) \
|
|
: tme_float_is_format(x, formats, TME_FLOAT_FORMAT_DOUBLE) \
|
|
? ((x)->tme_float_value_double < 0) \
|
|
: TME_FLOAT_IF_LONG_DOUBLE(((x)->tme_float_value_long_double < 0) ||) FALSE))
|
|
|
|
/* if possible, this returns a positive or negative infinity
|
|
float, otherwise, this returns the float value
|
|
closest to that infinity: */
|
|
float tme_float_infinity_float _TME_P((int));
|
|
|
|
/* if possible, this returns a negative zero float.
|
|
otherwise, this returns the negative float value closest
|
|
to zero: */
|
|
float tme_float_negative_zero_float _TME_P((void));
|
|
|
|
/* this returns the radix 2 mantissa and exponent of an in-range float.
|
|
the mantissa is either zero, or in the range [1,2): */
|
|
float tme_float_radix2_mantissa_exponent_float _TME_P((float, tme_int32_t *));
|
|
|
|
/* this scales a value by adding n to its exponent: */
|
|
float tme_float_radix2_scale_float _TME_P((float, tme_int32_t));
|
|
|
|
/* this returns the radix 10 mantissa and exponent of an in-range float.
|
|
the mantissa is either zero, or in the range [1,10): */
|
|
float tme_float_radix10_mantissa_exponent_float _TME_P((float, tme_int32_t *));
|
|
|
|
/* this scales a value by adding n to its exponent: */
|
|
float tme_float_radix10_scale_float _TME_P((float, tme_int32_t));
|
|
|
|
/* if possible, this returns a positive or negative infinity
|
|
double, otherwise, this returns the double value
|
|
closest to that infinity: */
|
|
double tme_float_infinity_double _TME_P((int));
|
|
|
|
/* if possible, this returns a negative zero double.
|
|
otherwise, this returns the negative double value closest
|
|
to zero: */
|
|
double tme_float_negative_zero_double _TME_P((void));
|
|
|
|
/* this returns the radix 2 mantissa and exponent of an in-range double.
|
|
the mantissa is either zero, or in the range [1,2): */
|
|
double tme_float_radix2_mantissa_exponent_double _TME_P((double, tme_int32_t *));
|
|
|
|
/* this scales a value by adding n to its exponent: */
|
|
double tme_float_radix2_scale_double _TME_P((double, tme_int32_t));
|
|
|
|
/* this returns the radix 10 mantissa and exponent of an in-range double.
|
|
the mantissa is either zero, or in the range [1,10): */
|
|
double tme_float_radix10_mantissa_exponent_double _TME_P((double, tme_int32_t *));
|
|
|
|
/* this scales a value by adding n to its exponent: */
|
|
double tme_float_radix10_scale_double _TME_P((double, tme_int32_t));
|
|
|
|
#ifdef _TME_HAVE_LONG_DOUBLE
|
|
|
|
/* if possible, this returns a positive or negative infinity
|
|
long double, otherwise, this returns the long double value
|
|
closest to that infinity: */
|
|
long double tme_float_infinity_long_double _TME_P((int));
|
|
|
|
/* if possible, this returns a negative zero long double.
|
|
otherwise, this returns the negative long double value closest
|
|
to zero: */
|
|
long double tme_float_negative_zero_long_double _TME_P((void));
|
|
|
|
/* this returns the radix 2 mantissa and exponent of an in-range long double.
|
|
the mantissa is either zero, or in the range [1,2): */
|
|
long double tme_float_radix2_mantissa_exponent_long_double _TME_P((long double, tme_int32_t *));
|
|
|
|
/* this scales a value by adding n to its exponent: */
|
|
long double tme_float_radix2_scale_long_double _TME_P((long double, tme_int32_t));
|
|
|
|
/* this returns the radix 10 mantissa and exponent of an in-range long double.
|
|
the mantissa is either zero, or in the range [1,10): */
|
|
long double tme_float_radix10_mantissa_exponent_long_double _TME_P((long double, tme_int32_t *));
|
|
|
|
/* this scales a value by adding n to its exponent: */
|
|
long double tme_float_radix10_scale_long_double _TME_P((long double, tme_int32_t));
|
|
|
|
#endif /* _TME_HAVE_LONG_DOUBLE */
|
|
|
|
/* prototypes for missing standard functions: */
|
|
#ifndef _TME_HAVE_ISINFF
|
|
int isinff _TME_P((float));
|
|
#endif /* !_TME_HAVE_ISINFF */
|
|
|
|
#endif /* _TME_GENERIC_FLOAT_H */
|