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 {
12 uint64_t sum, min, max;
13 unsigned i;
14
15 /*
16 * The integral of smoothstep in the [0..1] range equals 1/2. Verify
17 * that the fixed point representation's integral is no more than
18 * rounding error distant from 1/2. Regarding rounding, each table
19 * element is rounded down to the nearest fixed point value, so the
20 * integral may be off by as much as SMOOTHSTEP_NSTEPS ulps.
21 */
22 sum = 0;
23 for (i = 0; i < SMOOTHSTEP_NSTEPS; i++)
24 sum += smoothstep_tab[i];
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 {
41 uint64_t prev_h;
42 unsigned i;
43
44 /*
45 * The smoothstep function is monotonic in [0..1], i.e. its slope is
46 * non-negative. In practice we want to parametrize table generation
47 * such that piecewise slope is greater than zero, but do not require
48 * that here.
49 */
50 prev_h = 0;
51 for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) {
52 uint64_t h = smoothstep_tab[i];
53 assert_u64_ge(h, prev_h, "Piecewise non-monotonic, i=%u", i);
54 prev_h = h;
55 }
56 assert_u64_eq(smoothstep_tab[SMOOTHSTEP_NSTEPS-1],
57 (KQU(1) << SMOOTHSTEP_BFP), "Last step must equal 1");
58 }
59 TEST_END
60
TEST_BEGIN(test_smoothstep_slope)61 TEST_BEGIN(test_smoothstep_slope)
62 {
63 uint64_t prev_h, prev_delta;
64 unsigned i;
65
66 /*
67 * The smoothstep slope strictly increases until x=0.5, and then
68 * strictly decreases until x=1.0. Verify the slightly weaker
69 * requirement of monotonicity, so that inadequate table precision does
70 * not cause false test failures.
71 */
72 prev_h = 0;
73 prev_delta = 0;
74 for (i = 0; i < SMOOTHSTEP_NSTEPS / 2 + SMOOTHSTEP_NSTEPS % 2; i++) {
75 uint64_t h = smoothstep_tab[i];
76 uint64_t delta = h - prev_h;
77 assert_u64_ge(delta, prev_delta,
78 "Slope must monotonically increase in 0.0 <= x <= 0.5, "
79 "i=%u", i);
80 prev_h = h;
81 prev_delta = delta;
82 }
83
84 prev_h = KQU(1) << SMOOTHSTEP_BFP;
85 prev_delta = 0;
86 for (i = SMOOTHSTEP_NSTEPS-1; i >= SMOOTHSTEP_NSTEPS / 2; i--) {
87 uint64_t h = smoothstep_tab[i];
88 uint64_t delta = prev_h - h;
89 assert_u64_ge(delta, prev_delta,
90 "Slope must monotonically decrease in 0.5 <= x <= 1.0, "
91 "i=%u", i);
92 prev_h = h;
93 prev_delta = delta;
94 }
95 }
96 TEST_END
97
98 int
main(void)99 main(void)
100 {
101
102 return (test(
103 test_smoothstep_integral,
104 test_smoothstep_monotonic,
105 test_smoothstep_slope));
106 }
107