/* * vlibc — math.h todo-39 consolidated final test: slices S1..S4. * * One pass over every implemented todo-39 family, in all three * precisions, as a final smoke of the whole arithmetic slice: * * S1 fabs/fabsf/fabsl, copysign, floor, ceil, trunc * S2 round, rint, nearbyint, lrint, llrint, ilogb, logb * S3 frexp, ldexp, modf, scalbn, scalbln * S4 fmin, fmax, fdim, lround, llround, fmod, remainder, remquo * * Expected values follow IEEE 754-2008 / C23 semantics by hand and, for * the S4 families, the byte-exact host glibc 2.44 behavior that the * differential probe checks (the remquo quotient rows, in particular, are * glibc's tracked-low-bits values, e.g. remquo(100.0, 3.0) reports 1, the * low quotient bits, not 33). Inputs travel through volatile objects so * the compiler cannot constant-fold the calls away; diagnostics go * through raw SYS_write and no host headers are included. */ #include #include "../src/internal/syscall.h" /* Write a NUL-terminated string to fd via the raw syscall layer. */ static __attribute__((optimize("no-tree-loop-distribute-patterns"))) void say(int fd, const char *s) { long n = 0; while (s[n] != '\0') { n++; } __syscall3(SYS_write, fd, (long)s, n); } static int failures; static void check(int ok, const char *msg) { if (ok) { say(1, "ok "); } else { say(1, "FAIL "); failures++; } say(1, msg); say(1, "\n"); } /* S1: fabs, copysign, floor, ceil, trunc. */ static void s1_scenario(void) { volatile double negzero = -0.0; volatile double nan = NAN; volatile double big = 1e300; volatile float nanf = NAN; volatile long double nanl = NAN; check(fabs(-3.5) == 3.5, "fabs(-3.5) == 3.5"); check(fabs(negzero) == 0.0 && !signbit(fabs(negzero)), "fabs(-0.0) == +0.0"); check(fabs(nan) != nan, "fabs(NaN) is NaN"); check(copysign(3.0, -1.0) == -3.0, "copysign(3,-1) == -3"); check(copysign(-3.0, 1.0) == 3.0, "copysign(-3,1) == 3"); check(copysign(negzero, 1.0) == 0.0 && !signbit(copysign(negzero, 1.0)), "copysign(-0,+1) == +0"); check(floor(3.7) == 3.0, "floor(3.7) == 3"); check(floor(-3.7) == -4.0, "floor(-3.7) == -4"); check(floor(negzero) == 0.0 && signbit(floor(negzero)), "floor(-0.0) == -0.0"); check(ceil(3.2) == 4.0, "ceil(3.2) == 4"); check(ceil(-3.2) == -3.0, "ceil(-3.2) == -3"); check(trunc(3.7) == 3.0, "trunc(3.7) == 3"); check(trunc(-3.7) == -3.0, "trunc(-3.7) == -3"); check(fabsf(-2.5f) == 2.5f, "fabsf(-2.5f) == 2.5f"); check(fabsf(nanf) != nanf, "fabsf(NaN) is NaN"); check(copysignf(1.0f, -0.0f) == -1.0f, "copysignf(1,-0) == -1"); check(floorf(2.9f) == 2.0f, "floorf(2.9f) == 2"); check(ceilf(-2.1f) == -2.0f, "ceilf(-2.1f) == -2"); check(truncf(2.9f) == 2.0f, "truncf(2.9f) == 2"); check(fabsl(-3.5L) == 3.5L, "fabsl(-3.5L) == 3.5L"); check(fabsl(nanl) != nanl, "fabsl(NaN) is NaN"); check(copysignl(-4.0L, -2.0L) == -4.0L, "copysignl(-4,-2) == -4"); check(floorl(-3.7L) == -4.0L, "floorl(-3.7L) == -4"); check(ceill(3.2L) == 4.0L, "ceill(3.2L) == 4"); check(truncl(-3.7L) == -3.0L, "truncl(-3.7L) == -3"); check(floor(big) == big, "floor(1e300) == 1e300"); } /* S2: round, rint, nearbyint, lrint, llrint, ilogb, logb. */ static void s2_scenario(void) { volatile double negzero = -0.0; volatile double nan = NAN; volatile double sub = 0x1p-1074; volatile double two40 = 0x1p40; check(round(0.5) == 1.0, "round(0.5) == 1"); check(round(-0.5) == -1.0, "round(-0.5) == -1"); check(round(2.5) == 3.0, "round(2.5) == 3"); check(round(negzero) == 0.0 && signbit(round(negzero)), "round(-0.0) == -0.0"); check(round(sub) == 0.0 && !signbit(round(sub)), "round(5e-324) == +0"); check(isnan(round(nan)), "round(NaN) is NaN"); check(rint(0.5) == 0.0, "rint(0.5) == 0 (ties to even)"); check(rint(2.5) == 2.0, "rint(2.5) == 2 (ties to even)"); check(rint(negzero) == 0.0 && signbit(rint(negzero)), "rint(-0.0) == -0.0"); check(nearbyint(2.5) == 2.0, "nearbyint(2.5) == 2 (ties to even)"); check(nearbyint(1.5) == 2.0, "nearbyint(1.5) == 2"); check(lrint(2.5) == 2L, "lrint(2.5) == 2"); check(lrint(two40) == 1099511627776L, "lrint(2^40) == 2^40"); check(llrint(-2.5) == -2LL, "llrint(-2.5) == -2"); check(llrint(1.5) == 2LL, "llrint(1.5) == 2"); check(ilogb(8.0) == 3, "ilogb(8) == 3"); check(ilogb(0.5) == -1, "ilogb(0.5) == -1"); check(ilogb(sub) == -1074, "ilogb(min subnormal) == -1074"); check(ilogb(0.0) == FP_ILOGB0, "ilogb(0.0) == FP_ILOGB0"); check(logb(8.0) == 3.0, "logb(8) == 3"); check(logb(0.5) == -1.0, "logb(0.5) == -1"); check(logb(0.0) == -HUGE_VAL, "logb(0.0) == -Inf"); check(roundf(-0.5f) == -1.0f, "roundf(-0.5f) == -1"); check(rintf(2.5f) == 2.0f, "rintf(2.5f) == 2 (ties to even)"); check(nearbyintf(-2.5f) == -2.0f, "nearbyintf(-2.5f) == -2"); check(lrintf(1.5f) == 2L, "lrintf(1.5f) == 2"); check(llrintf(2.5f) == 2LL, "llrintf(2.5f) == 2"); check(ilogbf(0x1p-149f) == -149, "ilogbf(min subnormal) == -149"); check(logbf(8.0f) == 3.0f, "logbf(8) == 3"); check(roundl(2.5L) == 3.0L, "roundl(2.5L) == 3"); check(rintl(-0.5L) == 0.0L && signbit(rintl(-0.5L)), "rintl(-0.5L) == -0.0L"); check(nearbyintl(1.5L) == 2.0L, "nearbyintl(1.5L) == 2"); check(lrintl(2.5L) == 2L, "lrintl(2.5L) == 2"); check(llrintl(-2.5L) == -2LL, "llrintl(-2.5L) == -2"); check(ilogbl(0x1p-16445L) == -16445, "ilogbl(min subnormal) == -16445"); check(logbl(0.5L) == -1.0L, "logbl(0.5L) == -1"); } /* S3: frexp, ldexp, modf, scalbn, scalbln. */ static void s3_scenario(void) { volatile double negzero = -0.0; int e; double ip; double fp; float ipf; float fpf; long double ipl; long double fpl; check(frexp(8.0, &e) == 0.5 && e == 4, "frexp(8) == (0.5, 4)"); check(frexp(-6.0, &e) == -0.75 && e == 3, "frexp(-6) == (-0.75, 3)"); check(frexp(0.0, &e) == 0.0 && e == 0, "frexp(0) == (0, 0)"); check(frexp(negzero, &e) == 0.0 && e == 0, "frexp(-0) == (-0, 0)"); check(ldexp(1.0, 10) == 1024.0, "ldexp(1,10) == 1024"); check(ldexp(1.0, -1075) == 0.0, "ldexp(1,-1075) == +0"); check(scalbn(1.0, 10) == 1024.0, "scalbn(1,10) == 1024"); check(scalbln(1.0, 10L) == 1024.0, "scalbln(1,10) == 1024"); fp = modf(3.75, &ip); check(ip == 3.0 && fp == 0.75, "modf(3.75) == (3, 0.75)"); fp = modf(-3.75, &ip); check(ip == -3.0 && fp == -0.75, "modf(-3.75) == (-3, -0.75)"); check(frexpf(8.0f, &e) == 0.5f && e == 4, "frexpf(8) == (0.5, 4)"); check(ldexpf(1.0f, 10) == 1024.0f, "ldexpf(1,10) == 1024"); check(scalbnf(1.0f, -10) == 0.0009765625f, "scalbnf(1,-10) == 2^-10"); fpf = modff(3.75f, &ipf); check(ipf == 3.0f && fpf == 0.75f, "modff(3.75f) == (3, 0.75)"); check(frexpl(8.0L, &e) == 0.5L && e == 4, "frexpl(8) == (0.5, 4)"); check(ldexpl(1.0L, 10) == 1024.0L, "ldexpl(1,10) == 1024"); check(scalbnl(1.0L, 10) == 1024.0L, "scalbnl(1,10) == 1024"); fpl = modfl(3.75L, &ipl); check(ipl == 3.0L && fpl == 0.75L, "modfl(3.75L) == (3, 0.75)"); } /* S4a: fmin, fmax, fdim, lround, llround. */ static void s4_minmax_scenario(void) { volatile double negzero = -0.0; volatile double nan = NAN; volatile double inf = HUGE_VAL; volatile float nanf = NAN; volatile long double nanl = NAN; volatile double big = 1e300; volatile double huge = 1.7e308; volatile float bigf = 1e30f; check(fmin(3.0, 5.0) == 3.0, "fmin(3,5) == 3"); check(fmin(5.0, 3.0) == 3.0, "fmin(5,3) == 3"); check(fmin(3.0, 5.0) == 3.0, "fmin(3,5) == 3"); check(fmin(negzero, 0.0) == 0.0 && signbit(fmin(negzero, 0.0)), "fmin(-0,+0) == -0"); check(fmin(0.0, negzero) == 0.0 && signbit(fmin(0.0, negzero)), "fmin(+0,-0) == -0"); check(fmin(nan, 5.0) == 5.0, "fmin(NaN,5) == 5"); check(fmin(5.0, nan) == 5.0, "fmin(5,NaN) == 5"); check(isnan(fmin(nan, nan)), "fmin(NaN,NaN) is NaN"); check(fmax(3.0, 5.0) == 5.0, "fmax(3,5) == 5"); check(fmax(5.0, 3.0) == 5.0, "fmax(5,3) == 5"); check(fmax(negzero, 0.0) == 0.0 && !signbit(fmax(negzero, 0.0)), "fmax(-0,+0) == +0"); check(fmax(0.0, negzero) == 0.0 && !signbit(fmax(0.0, negzero)), "fmax(+0,-0) == +0"); check(fmax(nan, 5.0) == 5.0, "fmax(NaN,5) == 5"); check(fmax(5.0, nan) == 5.0, "fmax(5,NaN) == 5"); check(fmin(-inf, -5.0) == -inf, "fmin(-Inf,-5) == -Inf"); check(fmax(inf, 5.0) == inf, "fmax(+Inf,5) == +Inf"); check(fminf(3.0f, 5.0f) == 3.0f, "fminf(3,5) == 3"); check(fminf(nanf, 5.0f) == 5.0f, "fminf(NaN,5) == 5"); check(fmaxf(3.0f, 5.0f) == 5.0f, "fmaxf(3,5) == 5"); check(fminl(3.0L, 5.0L) == 3.0L, "fminl(3,5) == 3"); check(fminl(nanl, 5.0L) == 5.0L, "fminl(NaN,5) == 5"); check(fmaxl(3.0L, 5.0L) == 5.0L, "fmaxl(3,5) == 5"); check(fmaxl(nanl, 5.0L) == 5.0L, "fmaxl(NaN,5) == 5"); check(fdim(5.0, 3.0) == 2.0, "fdim(5,3) == 2"); check(fdim(3.0, 5.0) == 0.0 && !signbit(fdim(3.0, 5.0)), "fdim(3,5) == +0"); check(fdim(3.0, 3.0) == 0.0, "fdim(3,3) == +0"); check(fdim(inf, -inf) == inf, "fdim(+Inf,-Inf) == +Inf"); check(isnan(fdim(nan, 5.0)), "fdim(NaN,5) is NaN"); check(isnan(fdim(5.0, nan)), "fdim(5,NaN) is NaN"); check(fdim(big, -big) == 2.0 * big, "fdim(1e300,-1e300) == 2e300"); check(fdim(huge, -huge) == inf, "fdim(1.7e308,-1.7e308) == +Inf"); check(fdimf(5.0f, 3.0f) == 2.0f, "fdimf(5,3) == 2"); check(fdimf(3.0f, 5.0f) == 0.0f, "fdimf(3,5) == +0"); check(fdiml(5.0L, 3.0L) == 2.0L, "fdiml(5,3) == 2"); check(fdiml(3.0L, 5.0L) == 0.0L, "fdiml(3,5) == +0"); check(lround(0.5) == 1L, "lround(0.5) == 1"); check(lround(-0.5) == -1L, "lround(-0.5) == -1"); check(lround(2.5) == 3L, "lround(2.5) == 3"); check(lround(-2.5) == -3L, "lround(-2.5) == -3"); check(lround(big) == LONG_MIN, "lround(1e300) == LONG_MIN"); check(lround(-big) == LONG_MIN, "lround(-1e300) == LONG_MIN"); check(lroundf(2.5f) == 3L, "lroundf(2.5f) == 3"); check(lroundf(bigf) == LONG_MIN, "lroundf(1e30f) == LONG_MIN"); check(lroundl(2.5L) == 3L, "lroundl(2.5L) == 3"); check(llround(0.5) == 1LL, "llround(0.5) == 1"); check(llround(-0.5) == -1LL, "llround(-0.5) == -1"); check(llround(2.5) == 3LL, "llround(2.5) == 3"); check(llround(big) == LLONG_MIN, "llround(1e300) == LLONG_MIN"); check(llround(nan) == LLONG_MIN, "llround(NaN) == LLONG_MIN"); check(llroundf(2.5f) == 3LL, "llroundf(2.5f) == 3"); check(llroundl(2.5L) == 3LL, "llroundl(2.5L) == 3"); } /* S4b: fmod, remainder, remquo (glibc-verified rows). */ static void s4_rem_scenario(void) { volatile double negzero = -0.0; volatile double nan = NAN; volatile double inf = HUGE_VAL; volatile float nanf = NAN; volatile long double nanl = NAN; volatile double a100 = 100.0; volatile double a34 = 34.0; volatile double a40 = 40.0; volatile double a3 = 3.0; volatile double a5 = 5.0; volatile float f100 = 100.0f; volatile long double l100 = 100.0L; volatile long double l40 = 40.0L; int q; check(fmod(5.0, 3.0) == 2.0, "fmod(5,3) == 2"); check(fmod(-5.0, 3.0) == -2.0, "fmod(-5,3) == -2"); check(fmod(5.0, -3.0) == 2.0, "fmod(5,-3) == 2"); check(fmod(-5.0, -3.0) == -2.0, "fmod(-5,-3) == -2"); check(fmod(6.0, 3.0) == 0.0 && !signbit(fmod(6.0, 3.0)), "fmod(6,3) == +0"); check(fmod(-6.0, 3.0) == 0.0 && signbit(fmod(-6.0, 3.0)), "fmod(-6,3) == -0"); check(fmod(3.0, 5.0) == 3.0, "fmod(3,5) == 3"); check(fmod(negzero, 5.0) == 0.0 && signbit(fmod(negzero, 5.0)), "fmod(-0,5) == -0"); check(fmod(5.0, inf) == 5.0, "fmod(5,+Inf) == 5"); check(isnan(fmod(5.0, 0.0)), "fmod(5,0) is NaN"); check(isnan(fmod(inf, 3.0)), "fmod(+Inf,3) is NaN"); check(isnan(fmod(nan, 3.0)), "fmod(NaN,3) is NaN"); check(fmodf(5.0f, 3.0f) == 2.0f, "fmodf(5,3) == 2"); check(fmodf(-5.0f, 3.0f) == -2.0f, "fmodf(-5,3) == -2"); check(fmodf(5.0f, 0.0f) != 0 && !(fmodf(5.0f, 0.0f) == fmodf(5.0f, 0.0f)), "fmodf(5,0) is NaN"); check(isnan(fmodf(nanf, 3.0f)), "fmodf(NaN,3) is NaN"); check(fmodl(5.0L, 3.0L) == 2.0L, "fmodl(5,3) == 2"); check(fmodl(-5.0L, 3.0L) == -2.0L, "fmodl(-5,3) == -2"); check(fmodl(5.0L, 0.0L) != fmodl(5.0L, 0.0L), "fmodl(5,0) is NaN"); check(isnan(fmodl(nanl, 3.0L)), "fmodl(NaN,3) is NaN"); check(remainder(5.0, 3.0) == -1.0, "remainder(5,3) == -1"); check(remainder(5.0, 2.0) == 1.0, "remainder(5,2) == 1"); check(remainder(6.0, 4.0) == -2.0, "remainder(6,4) == -2"); check(remainder(7.0, 4.0) == -1.0, "remainder(7,4) == -1"); check(remainder(5.0, 5.0) == 0.0, "remainder(5,5) == +0"); check(remainder(-5.0, 3.0) == 1.0, "remainder(-5,3) == 1"); check(remainder(5.0, -3.0) == -1.0, "remainder(5,-3) == -1"); check(isnan(remainder(5.0, 0.0)), "remainder(5,0) is NaN"); check(isnan(remainder(inf, 3.0)), "remainder(+Inf,3) is NaN"); check(isnan(remainder(nan, 3.0)), "remainder(NaN,3) is NaN"); check(remainderf(5.0f, 3.0f) == -1.0f, "remainderf(5,3) == -1"); check(isnan(remainderf(5.0f, 0.0f)), "remainderf(5,0) is NaN"); check(remainderl(5.0L, 3.0L) == -1.0L, "remainderl(5,3) == -1"); check(isnan(remainderl(5.0L, 0.0L)), "remainderl(5,0) is NaN"); check(remainderl(-5.0L, 3.0L) == 1.0L, "remainderl(-5,3) == 1"); check(remquo(5.0, 3.0, &q) == -1.0 && q == 2, "remquo(5,3): r=-1 q=2"); check(remquo(-5.0, 3.0, &q) == 1.0 && q == -2, "remquo(-5,3): r=1 q=-2"); check(remquo(5.0, -3.0, &q) == -1.0 && q == -2, "remquo(5,-3): r=-1 q=-2"); check(remquo(a100, a3, &q) == 1.0 && q == 1, "remquo(100,3): r=1 q=1"); check(remquo(a34, a3, &q) == 1.0 && q == 3, "remquo(34,3): r=1 q=3"); check(remquo(a40, a3, &q) == 1.0 && q == 5, "remquo(40,3): r=1 q=5"); check(remquo(7.0, 2.0, &q) == -1.0 && q == 4, "remquo(7,2): r=-1 q=4"); check(remquo(6.0, 3.0, &q) == 0.0 && q == 2, "remquo(6,3): r=0 q=2"); check(remquo(2.0, 3.0, &q) == -1.0 && q == 1, "remquo(2,3): r=-1 q=1"); check(remquo(1.0, 3.0, &q) == 1.0 && q == 0, "remquo(1,3): r=1 q=0"); check(remquo(a5, a5, &q) == 0.0 && q == 1, "remquo(5,5): r=0 q=1"); check(isnan(remquo(a5, 0.0, &q)), "remquo(5,0) is NaN"); check(isnan(remquo(inf, a3, &q)), "remquo(+Inf,3) is NaN"); check(remquof(f100, 3.0f, &q) == 1.0f && q == 1, "remquof(100,3): q=1"); check(remquof(5.0f, 3.0f, &q) == -1.0f && q == 2, "remquof(5,3): q=2"); check(remquol(l100, 3.0L, &q) == 1.0L && q == 1, "remquol(100,3): q=1"); check(remquol(5.0L, 3.0L, &q) == -1.0L && q == 2, "remquol(5,3): q=2"); check(remquol(l40, 3.0L, &q) == 1.0L && q == 5, "remquol(40,3): q=5"); check(isnan(remquol(nanl, 3.0L, &q)), "remquol(NaN,3) is NaN"); } int main(void) { s1_scenario(); s2_scenario(); s3_scenario(); s4_minmax_scenario(); s4_rem_scenario(); if (failures == 0) { say(1, "all math todo-39 (S1-S4) tests passed\n"); } else { say(1, "FAILURES\n"); } return failures == 0 ? 0 : 1; }