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);
float floorf(float);
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);
float fmaxf(float, float);
long double fmaxl(long double, long double);

View File

@ -32,6 +32,16 @@
long double: fn##l, \
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_y(fn,x,y) __tg_real_x_y(fn,(x),(y))
@ -54,6 +64,7 @@
#define expm1(x) __tg_real_x(expm1,(x))
#define fabs(x) __tg_real_x(fabs,(x))
#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 fmin(x,y) __tg_real_x_y(fmin,(x),(y))
#define floor(x) __tg_real_x(floor,(x))

View File

@ -48,6 +48,14 @@ int main(void) {
goto Fail; \
} 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) \
if ((op) != (val)) \
goto Fail
@ -361,7 +369,7 @@ int main(void) {
expect_pole_error(tgammaf(-0.0), -INFINITY);
expect_domain_error(tgammal(-2.0));
expect_domain_error(tgammal(-15.0));
expect_domain_error(tgammal(-1e4900));
expect_domain_error(tgammal(-1e4900L));
expect_domain_error(tgammal(-INFINITY));
expect_exact(tgammal(+INFINITY),+INFINITY);
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(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(strtold("-InFin", &p), -INFINITY); expect_exact(*p, 'i');
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))
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");
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.
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);
float fmaxf(float x, float y);
long double fmaxl(long double x, long double y);