Add tests and documentation for fma().

This commit is contained in:
Stephen Heumann 2023-04-02 16:31:28 -05:00
parent a988ef60bc
commit c678151bde
5 changed files with 192 additions and 1 deletions

View File

@ -126,6 +126,9 @@ long double fdiml(long double, long double);
double floor(double); double floor(double);
float floorf(float); float floorf(float);
long double floorl(long double); long double floorl(long double);
double fma(double, double, double);
float fmaf(float, float, float);
long double fmal(long double, long double, long double);
double fmax(double, double); double fmax(double, double);
float fmaxf(float, float); float fmaxf(float, float);
long double fmaxl(long double, long double); long double fmaxl(long double, long double);

View File

@ -32,6 +32,16 @@
long double: fn##l, \ long double: fn##l, \
default: _Generic((y), long double: fn##l, default: fn))((x),(y),(other)) default: _Generic((y), long double: fn##l, default: fn))((x),(y),(other))
#define __tg_real_x_y_z(fn,x,y,z) _Generic((x), \
float: _Generic((y), \
float: _Generic((z), float: fn##f, long double: fn##l, default: fn), \
long double: fn##l, \
default: _Generic((z), long double: fn##l, default: fn)), \
long double: fn##l, \
default: _Generic((y), \
long double: fn##l, \
default: _Generic((z), long double: fn##l, default: fn)))((x),(y),(z))
#define __tg_x(fn,x) __tg_real_x(fn,(x)) #define __tg_x(fn,x) __tg_real_x(fn,(x))
#define __tg_x_y(fn,x,y) __tg_real_x_y(fn,(x),(y)) #define __tg_x_y(fn,x,y) __tg_real_x_y(fn,(x),(y))
@ -54,6 +64,7 @@
#define expm1(x) __tg_real_x(expm1,(x)) #define expm1(x) __tg_real_x(expm1,(x))
#define fabs(x) __tg_real_x(fabs,(x)) #define fabs(x) __tg_real_x(fabs,(x))
#define fdim(x,y) __tg_real_x_y(fdim,(x),(y)) #define fdim(x,y) __tg_real_x_y(fdim,(x),(y))
#define fma(x,y,z) __tg_real_x_y_z(fma,(x),(y),(z))
#define fmax(x,y) __tg_real_x_y(fmax,(x),(y)) #define fmax(x,y) __tg_real_x_y(fmax,(x),(y))
#define fmin(x,y) __tg_real_x_y(fmin,(x),(y)) #define fmin(x,y) __tg_real_x_y(fmin,(x),(y))
#define floor(x) __tg_real_x(floor,(x)) #define floor(x) __tg_real_x(floor,(x))

View File

@ -48,6 +48,14 @@ int main(void) {
goto Fail; \ goto Fail; \
} while (0) } while (0)
#define expect_underflow(op, val) do { \
feclearexcept(FE_ALL_EXCEPT); \
if ((op) != (val)) \
goto Fail; \
if (!fetestexcept(FE_UNDERFLOW)) \
goto Fail; \
} while (0)
#define expect_exact(op, val) \ #define expect_exact(op, val) \
if ((op) != (val)) \ if ((op) != (val)) \
goto Fail goto Fail
@ -361,7 +369,7 @@ int main(void) {
expect_pole_error(tgammaf(-0.0), -INFINITY); expect_pole_error(tgammaf(-0.0), -INFINITY);
expect_domain_error(tgammal(-2.0)); expect_domain_error(tgammal(-2.0));
expect_domain_error(tgammal(-15.0)); expect_domain_error(tgammal(-15.0));
expect_domain_error(tgammal(-1e4900)); expect_domain_error(tgammal(-1e4900L));
expect_domain_error(tgammal(-INFINITY)); expect_domain_error(tgammal(-INFINITY));
expect_exact(tgammal(+INFINITY),+INFINITY); expect_exact(tgammal(+INFINITY),+INFINITY);
expect_approx(tgammal(1.0), 1.0); expect_approx(tgammal(1.0), 1.0);
@ -565,6 +573,37 @@ int main(void) {
expect_exact(fminl(-50.0, NAN), -50.0); expect_exact(fminl(-50.0, NAN), -50.0);
expect_exact(fminl(NAN, 1e30L), 1e30L); expect_exact(fminl(NAN, 1e30L), 1e30L);
expect_nan(fma(+INFINITY, +0.0, NAN));
expect_nan(fmaf(-0.0, -INFINITY, NAN));
expect_domain_error(fmal(-INFINITY, +0.0, 123.0));
expect_domain_error(fma(-0.0, +INFINITY, -INFINITY));
expect_domain_error(fmaf(1e-10, -INFINITY, +INFINITY));
expect_domain_error(fmal(+INFINITY, 1e-4950L, -INFINITY));
expect_exact(fma(2.0, 3.0, 5.0), 11.0);
expect_exact(fmal(2e50L, -3.0L, 5e50L), -1e50L);
expect_exact(fmaf(-2.0, -3.0, -7.5), -1.5);
expect_nan(fma(NAN, 1.23, 4.56));
expect_nan(fmaf(1.23, NAN, 4.56));
expect_nan(fmal(1.23, 4.56, NAN));
expect_exact(fmal(+INFINITY, LDBL_TRUE_MIN, -1e4932L), +INFINITY);
expect_overflow(fmal(1e4000L, 1e1000L, -1e4932L), +INFINITY);
expect_exact(fmal(LDBL_MAX, 1.0, LDBL_TRUE_MIN), LDBL_MAX);
expect_exact(fmal(-LDBL_MAX, 1.0, -LDBL_TRUE_MIN), -LDBL_MAX);
fesetround(FE_UPWARD);
expect_overflow(fmal(LDBL_MAX, 1.0, LDBL_TRUE_MIN), +INFINITY);
expect_exact(fmal(-LDBL_MAX, 1.0, -LDBL_TRUE_MIN), -LDBL_MAX);
fesetround(FE_DOWNWARD);
expect_exact(fmal(LDBL_MAX, 1.0, LDBL_TRUE_MIN), LDBL_MAX);
expect_overflow(fmal(-LDBL_MAX, 1.0, -LDBL_TRUE_MIN), -INFINITY);
fesetround(FE_TOWARDZERO);
expect_exact(fmal(LDBL_MAX, 1.0, LDBL_TRUE_MIN), LDBL_MAX);
expect_exact(fmal(-LDBL_MAX, 1.0, -LDBL_TRUE_MIN), -LDBL_MAX);
expect_underflow(fmal(-LDBL_TRUE_MIN, LDBL_TRUE_MIN, LDBL_TRUE_MIN), 0.0);
fesetenv(FE_DFL_ENV);
expect_exact(fmal(-LDBL_TRUE_MIN, LDBL_TRUE_MIN, LDBL_TRUE_MIN), LDBL_TRUE_MIN);
expect_underflow(fmal(-LDBL_TRUE_MIN, LDBL_TRUE_MIN, 0.0), -0.0);
expect_exact(fmal(LDBL_TRUE_MIN, 5.0, -LDBL_TRUE_MIN), LDBL_TRUE_MIN*4.0L);
expect_exact(strtod("-1.25e+3x", &p), -1250.0); expect_exact(*p, 'x'); expect_exact(strtod("-1.25e+3x", &p), -1250.0); expect_exact(*p, 'x');
expect_exact(strtold("-InFin", &p), -INFINITY); expect_exact(*p, 'i'); expect_exact(strtold("-InFin", &p), -INFINITY); expect_exact(*p, 'i');
expect_exact(strtof("INFiniTy", &p), INFINITY); //expect_exact(*p, 0); expect_exact(strtof("INFiniTy", &p), INFINITY); //expect_exact(*p, 0);

View File

@ -77,6 +77,138 @@ int main(void) {
if (sizeof(nextafter(1LL, 20LL)) != sizeof(double)) if (sizeof(nextafter(1LL, 20LL)) != sizeof(double))
goto Fail; goto Fail;
if (sizeof(fma(1.0F, 1.0F, 1.0F)) != sizeof(float))
goto Fail;
if (sizeof(fma(1.0F, 1.0F, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0F, 1.0F, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0F, 1.0F, 1LL)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0F, 1.0, 1.0F)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0F, 1.0, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0F, 1.0, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0F, 1.0, 1LL)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0F, 1.0L, 1.0F)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0F, 1.0L, 1.0)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0F, 1.0L, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0F, 1.0L, 1LL)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0F, 1L, 1.0F)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0F, 1L, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0F, 1L, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0F, 1L, 1LL)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1.0F, 1.0F)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1.0F, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1.0F, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0, 1.0F, 1LL)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1.0, 1.0F)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1.0, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1.0, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0, 1.0, 1LL)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1.0L, 1.0F)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0, 1.0L, 1.0)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0, 1.0L, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0, 1.0L, 1LL)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0, 1L, 1.0F)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1L, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0, 1L, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0, 1L, 1LL)) != sizeof(double))
goto Fail;
if (sizeof(fma(1.0L, 1.0F, 1.0F)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0F, 1.0)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0F, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0F, 1LL)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0, 1.0F)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0, 1.0)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0, 1LL)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0L, 1.0F)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0L, 1.0)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0L, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1.0L, 1LL)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1L, 1.0F)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1L, 1.0)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1L, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1.0L, 1L, 1LL)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1LL, 1.0F, 1.0F)) != sizeof(double))
goto Fail;
if (sizeof(fma(1LL, 1.0F, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1LL, 1.0F, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1LL, 1.0F, 1LL)) != sizeof(double))
goto Fail;
if (sizeof(fma(1LL, 1.0, 1.0F)) != sizeof(double))
goto Fail;
if (sizeof(fma(1LL, 1.0, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1LL, 1.0, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1LL, 1.0, 1LL)) != sizeof(double))
goto Fail;
if (sizeof(fma(1LL, 1.0L, 1.0F)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1LL, 1.0L, 1.0)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1LL, 1.0L, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1LL, 1.0L, 1LL)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1LL, 1L, 1.0F)) != sizeof(double))
goto Fail;
if (sizeof(fma(1LL, 1L, 1.0)) != sizeof(double))
goto Fail;
if (sizeof(fma(1LL, 1L, 1.0L)) != sizeof(long double))
goto Fail;
if (sizeof(fma(1LL, 1L, 1LL)) != sizeof(double))
goto Fail;
printf ("Passed Conformance Test c99tgmath\n"); printf ("Passed Conformance Test c99tgmath\n");
return 0; return 0;

View File

@ -1218,6 +1218,12 @@ long double fdiml(long double x, long double y);
These functions return x - y if x > y, or +0.0 if x <= y. These functions return x - y if x > y, or +0.0 if x <= y.
double fma(double x, double y, double z);
float fmaf(float x, float y, float z);
long double fmal(long double x, long double y, long double z);
These functions compute (x * y) + z, rounded as one ternary operation. That is, they behave as if the mathematical result is computed exactly and then rounded once to produce the return value.
double fmax(double x, double y); double fmax(double x, double y);
float fmaxf(float x, float y); float fmaxf(float x, float y);
long double fmaxl(long double x, long double y); long double fmaxl(long double x, long double y);