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