huangcm
2024-12-18 9d29be7f7249789d6ffd0440067187a9f040c2cd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#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));
}