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