mirror of
https://git.musl-libc.org/git/musl
synced 2025-02-10 07:14:15 +03:00
math: more correct tgmath.h type cast logic
__IS_FP is a portable integer constant expression now (uses that unsigned long long is larger than float) the result casting logic should work now on all compilers supporting typeof
This commit is contained in:
parent
e9e2b66e68
commit
3c4214db72
@ -13,7 +13,7 @@ sizeof(double) == sizeof(long double)
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
|
|
||||||
#define __IS_FP(x) !!((1?1:(x))/2)
|
#define __IS_FP(x) (sizeof((x)+1ULL) == sizeof((x)+1.0f))
|
||||||
#define __IS_CX(x) (__IS_FP(x) && sizeof(x) == sizeof((x)+I))
|
#define __IS_CX(x) (__IS_FP(x) && sizeof(x) == sizeof((x)+I))
|
||||||
#define __IS_REAL(x) (__IS_FP(x) && 2*sizeof(x) == sizeof((x)+I))
|
#define __IS_REAL(x) (__IS_FP(x) && 2*sizeof(x) == sizeof((x)+I))
|
||||||
|
|
||||||
@ -28,57 +28,42 @@ sizeof(double) == sizeof(long double)
|
|||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
/*
|
/*
|
||||||
the conditional expression (that selects the right function
|
the result must be casted to the right type
|
||||||
for evaluation) should be casted to the return type of the
|
(otherwise the result type is determined by the conversion
|
||||||
selected function (otherwise the result type is determined
|
rules applied to all the function return types so it is long
|
||||||
by the conversion rules applied to all the function return
|
double or long double complex except for integral functions)
|
||||||
types so it is long double or long double _Complex)
|
|
||||||
|
|
||||||
this cannot be done in c99 (c11 has _Generic that would help
|
this cannot be done in c99, so the typeof gcc extension is
|
||||||
but is not yet widely supported), so the typeof extension of
|
used and that the type of ?: depends on wether an operand is
|
||||||
gcc is used and that ?: has special semantics when one of
|
a null pointer constant or not
|
||||||
the operands is a null pointer constant
|
(in c11 _Generic can be used)
|
||||||
|
|
||||||
unfortunately the standard is overly strict about the
|
the c arguments below must be integer constant expressions
|
||||||
definition of null pointer constants (current gcc does not
|
so they can be in null pointer constants
|
||||||
follow the standard but clang does) so we have to use a hack
|
(__IS_FP above was carefully chosen this way)
|
||||||
to be able to tell integer and floating-point types apart:
|
|
||||||
both gcc and clang evaluate sizeof(void) to 1 even though it
|
|
||||||
is a constraint violation, we only use this on clang for now
|
|
||||||
*/
|
*/
|
||||||
/* predicates that evaluate to integer constant expressions */
|
|
||||||
#ifdef __clang__
|
|
||||||
/* TODO: __c_IS_FP(1.0) is a constraint violation */
|
|
||||||
#define __c_IS_FP(x) (!(sizeof*(__typeof__(0?(int*)0:(void*)__IS_FP(x)))0-1))
|
|
||||||
#else
|
|
||||||
#define __c_IS_FP(x) __IS_FP(x)
|
|
||||||
#endif
|
|
||||||
#define __c_IS_CX(x) (__c_IS_FP(x) && sizeof(x) == sizeof((x)+I))
|
|
||||||
#define __c_FLTCX(x) (__c_IS_CX(x) && sizeof(x) == sizeof(float complex))
|
|
||||||
#define __c_DBLCX(x) (__c_IS_CX(x) && sizeof(x) == sizeof(double complex))
|
|
||||||
#define __c_LDBLCX(x) (__c_IS_CX(x) && sizeof(x) == sizeof(long double complex) && sizeof(long double) != sizeof(double))
|
|
||||||
/* if c then t else void */
|
/* if c then t else void */
|
||||||
#define __type1(c,t) __typeof__(*(0?(t*)0:(void*)!(c)))
|
#define __type1(c,t) __typeof__(*(0?(t*)0:(void*)!(c)))
|
||||||
/* if c then t1 else t2 */
|
/* if c then t1 else t2 */
|
||||||
#define __type2(c,t1,t2) __typeof__(*(0?(__type1(c,t1)*)0:(__type1(!(c),t2)*)0))
|
#define __type2(c,t1,t2) __typeof__(*(0?(__type1(c,t1)*)0:(__type1(!(c),t2)*)0))
|
||||||
/* cast to double when x is integral, otherwise use typeof(x) */
|
/* cast to double when x is integral, otherwise use typeof(x) */
|
||||||
#define __RETCAST(x) ( \
|
#define __RETCAST(x) ( \
|
||||||
__type2(__c_IS_FP(x), __typeof__(x), double))
|
__type2(__IS_FP(x), __typeof__(x), double))
|
||||||
/* 2 args case, should work for complex types (cpow) */
|
/* 2 args case, should work for complex types (cpow) */
|
||||||
#define __RETCAST_2(x, y) ( \
|
#define __RETCAST_2(x, y) ( \
|
||||||
__type2(__c_IS_FP(x) && __c_IS_FP(y), \
|
__type2(__IS_FP(x) && __IS_FP(y), \
|
||||||
__typeof__((x)+(y)), \
|
__typeof__((x)+(y)), \
|
||||||
__typeof__((x)+(y)+1.0)))
|
__typeof__((x)+(y)+1.0)))
|
||||||
/* 3 args case (fma only) */
|
/* 3 args case (fma only) */
|
||||||
#define __RETCAST_3(x, y, z) ( \
|
#define __RETCAST_3(x, y, z) ( \
|
||||||
__type2(__c_IS_FP(x) && __c_IS_FP(y) && __c_IS_FP(z), \
|
__type2(__IS_FP(x) && __IS_FP(y) && __IS_FP(z), \
|
||||||
__typeof__((x)+(y)+(z)), \
|
__typeof__((x)+(y)+(z)), \
|
||||||
__typeof__((x)+(y)+(z)+1.0)))
|
__typeof__((x)+(y)+(z)+1.0)))
|
||||||
/* drop complex from the type of x */
|
/* drop complex from the type of x */
|
||||||
/* TODO: wrong when sizeof(long double)==sizeof(double) */
|
/* TODO: wrong when sizeof(long double)==sizeof(double) */
|
||||||
#define __RETCAST_REAL(x) ( \
|
#define __RETCAST_REAL(x) ( \
|
||||||
__type2(sizeof(__RETCAST(x)0+I)==sizeof(float complex), float, \
|
__type2(__IS_FP(x) && sizeof((x)+I) == sizeof(float complex), float, \
|
||||||
__type2(sizeof(__RETCAST(x)0+I)==sizeof(double complex), double, \
|
__type2(sizeof((x)+1.0+I) == sizeof(double complex), double, \
|
||||||
long double)))
|
long double)))
|
||||||
/* add complex to the type of x */
|
/* add complex to the type of x */
|
||||||
#define __RETCAST_CX(x) (__typeof__(__RETCAST(x)0+I))
|
#define __RETCAST_CX(x) (__typeof__(__RETCAST(x)0+I))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user