1 #include "test/jemalloc_test.h"
2
3 static const uint64_t smoothstep_tab[] = {
4 #define STEP(step, h, x, y) \
5 h,
6 SMOOTHSTEP
7 #undef STEP
8 };
9
TEST_BEGIN(test_smoothstep_integral)10 TEST_BEGIN(test_smoothstep_integral) {
11 uint64_t sum, min, max;
12 unsigned i;
13
14 /*
15 * The integral of smoothstep in the [0..1] range equals 1/2. Verify
16 * that the fixed point representation's integral is no more than
17 * rounding error distant from 1/2. Regarding rounding, each table
18 * element is rounded down to the nearest fixed point value, so the
19 * integral may be off by as much as SMOOTHSTEP_NSTEPS ulps.
20 */
21 sum = 0;
22 for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) {
23 sum += smoothstep_tab[i];
24 }
25
26 max = (KQU(1) << (SMOOTHSTEP_BFP-1)) * (SMOOTHSTEP_NSTEPS+1);
27 min = max - SMOOTHSTEP_NSTEPS;
28
29 assert_u64_ge(sum, min,
30 "Integral too small, even accounting for truncation");
31 assert_u64_le(sum, max, "Integral exceeds 1/2");
32 if (false) {
33 malloc_printf("%"FMTu64" ulps under 1/2 (limit %d)\n",
34 max - sum, SMOOTHSTEP_NSTEPS);
35 }
36 }
37 TEST_END
38
TEST_BEGIN(test_smoothstep_monotonic)39 TEST_BEGIN(test_smoothstep_monotonic) {
40 uint64_t prev_h;
41 unsigned i;
42
43 /*
44 * The smoothstep function is monotonic in [0..1], i.e. its slope is
45 * non-negative. In practice we want to parametrize table generation
46 * such that piecewise slope is greater than zero, but do not require
47 * that here.
48 */
49 prev_h = 0;
50 for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) {
51 uint64_t h = smoothstep_tab[i];
52 assert_u64_ge(h, prev_h, "Piecewise non-monotonic, i=%u", i);
53 prev_h = h;
54 }
55 assert_u64_eq(smoothstep_tab[SMOOTHSTEP_NSTEPS-1],
56 (KQU(1) << SMOOTHSTEP_BFP), "Last step must equal 1");
57 }
58 TEST_END
59
TEST_BEGIN(test_smoothstep_slope)60 TEST_BEGIN(test_smoothstep_slope) {
61 uint64_t prev_h, prev_delta;
62 unsigned i;
63
64 /*
65 * The smoothstep slope strictly increases until x=0.5, and then
66 * strictly decreases until x=1.0. Verify the slightly weaker
67 * requirement of monotonicity, so that inadequate table precision does
68 * not cause false test failures.
69 */
70 prev_h = 0;
71 prev_delta = 0;
72 for (i = 0; i < SMOOTHSTEP_NSTEPS / 2 + SMOOTHSTEP_NSTEPS % 2; i++) {
73 uint64_t h = smoothstep_tab[i];
74 uint64_t delta = h - prev_h;
75 assert_u64_ge(delta, prev_delta,
76 "Slope must monotonically increase in 0.0 <= x <= 0.5, "
77 "i=%u", i);
78 prev_h = h;
79 prev_delta = delta;
80 }
81
82 prev_h = KQU(1) << SMOOTHSTEP_BFP;
83 prev_delta = 0;
84 for (i = SMOOTHSTEP_NSTEPS-1; i >= SMOOTHSTEP_NSTEPS / 2; i--) {
85 uint64_t h = smoothstep_tab[i];
86 uint64_t delta = prev_h - h;
87 assert_u64_ge(delta, prev_delta,
88 "Slope must monotonically decrease in 0.5 <= x <= 1.0, "
89 "i=%u", i);
90 prev_h = h;
91 prev_delta = delta;
92 }
93 }
94 TEST_END
95
96 int
main(void)97 main(void) {
98 return test(
99 test_smoothstep_integral,
100 test_smoothstep_monotonic,
101 test_smoothstep_slope);
102 }
103