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