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