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 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 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 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 99 main(void) 100 { 101 102 return (test( 103 test_smoothstep_integral, 104 test_smoothstep_monotonic, 105 test_smoothstep_slope)); 106 } 107