| #include "test/jemalloc_test.h" |
| |
| static const uint64_t smoothstep_tab[] = { |
| #define STEP(step, h, x, y) \ |
| h, |
| SMOOTHSTEP |
| #undef STEP |
| }; |
| |
| TEST_BEGIN(test_smoothstep_integral) |
| { |
| uint64_t sum, min, max; |
| unsigned i; |
| |
| /* |
| * The integral of smoothstep in the [0..1] range equals 1/2. Verify |
| * that the fixed point representation's integral is no more than |
| * rounding error distant from 1/2. Regarding rounding, each table |
| * element is rounded down to the nearest fixed point value, so the |
| * integral may be off by as much as SMOOTHSTEP_NSTEPS ulps. |
| */ |
| sum = 0; |
| for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) |
| sum += smoothstep_tab[i]; |
| |
| max = (KQU(1) << (SMOOTHSTEP_BFP-1)) * (SMOOTHSTEP_NSTEPS+1); |
| min = max - SMOOTHSTEP_NSTEPS; |
| |
| assert_u64_ge(sum, min, |
| "Integral too small, even accounting for truncation"); |
| assert_u64_le(sum, max, "Integral exceeds 1/2"); |
| if (false) { |
| malloc_printf("%"FMTu64" ulps under 1/2 (limit %d)\n", |
| max - sum, SMOOTHSTEP_NSTEPS); |
| } |
| } |
| TEST_END |
| |
| TEST_BEGIN(test_smoothstep_monotonic) |
| { |
| uint64_t prev_h; |
| unsigned i; |
| |
| /* |
| * The smoothstep function is monotonic in [0..1], i.e. its slope is |
| * non-negative. In practice we want to parametrize table generation |
| * such that piecewise slope is greater than zero, but do not require |
| * that here. |
| */ |
| prev_h = 0; |
| for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) { |
| uint64_t h = smoothstep_tab[i]; |
| assert_u64_ge(h, prev_h, "Piecewise non-monotonic, i=%u", i); |
| prev_h = h; |
| } |
| assert_u64_eq(smoothstep_tab[SMOOTHSTEP_NSTEPS-1], |
| (KQU(1) << SMOOTHSTEP_BFP), "Last step must equal 1"); |
| } |
| TEST_END |
| |
| TEST_BEGIN(test_smoothstep_slope) |
| { |
| uint64_t prev_h, prev_delta; |
| unsigned i; |
| |
| /* |
| * The smoothstep slope strictly increases until x=0.5, and then |
| * strictly decreases until x=1.0. Verify the slightly weaker |
| * requirement of monotonicity, so that inadequate table precision does |
| * not cause false test failures. |
| */ |
| prev_h = 0; |
| prev_delta = 0; |
| for (i = 0; i < SMOOTHSTEP_NSTEPS / 2 + SMOOTHSTEP_NSTEPS % 2; i++) { |
| uint64_t h = smoothstep_tab[i]; |
| uint64_t delta = h - prev_h; |
| assert_u64_ge(delta, prev_delta, |
| "Slope must monotonically increase in 0.0 <= x <= 0.5, " |
| "i=%u", i); |
| prev_h = h; |
| prev_delta = delta; |
| } |
| |
| prev_h = KQU(1) << SMOOTHSTEP_BFP; |
| prev_delta = 0; |
| for (i = SMOOTHSTEP_NSTEPS-1; i >= SMOOTHSTEP_NSTEPS / 2; i--) { |
| uint64_t h = smoothstep_tab[i]; |
| uint64_t delta = prev_h - h; |
| assert_u64_ge(delta, prev_delta, |
| "Slope must monotonically decrease in 0.5 <= x <= 1.0, " |
| "i=%u", i); |
| prev_h = h; |
| prev_delta = delta; |
| } |
| } |
| TEST_END |
| |
| int |
| main(void) |
| { |
| |
| return (test( |
| test_smoothstep_integral, |
| test_smoothstep_monotonic, |
| test_smoothstep_slope)); |
| } |