2016-02-06 16:46:19 +08:00
|
|
|
#include "test/jemalloc_test.h"
|
|
|
|
|
|
|
|
static const uint64_t smoothstep_tab[] = {
|
2017-03-18 03:42:33 +08:00
|
|
|
#define STEP(step, h, x, y, h_sum) \
|
2016-02-06 16:46:19 +08:00
|
|
|
h,
|
|
|
|
SMOOTHSTEP
|
|
|
|
#undef STEP
|
|
|
|
};
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
TEST_BEGIN(test_smoothstep_integral) {
|
2016-02-06 16:46:19 +08:00
|
|
|
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;
|
2017-01-16 08:56:30 +08:00
|
|
|
for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) {
|
2016-02-06 16:46:19 +08:00
|
|
|
sum += smoothstep_tab[i];
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2016-02-06 16:46:19 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
TEST_BEGIN(test_smoothstep_monotonic) {
|
2016-02-06 16:46:19 +08:00
|
|
|
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
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
TEST_BEGIN(test_smoothstep_slope) {
|
2016-02-06 16:46:19 +08:00
|
|
|
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
|
2017-01-16 08:56:30 +08:00
|
|
|
main(void) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return test(
|
2016-02-06 16:46:19 +08:00
|
|
|
test_smoothstep_integral,
|
|
|
|
test_smoothstep_monotonic,
|
2017-01-20 10:15:45 +08:00
|
|
|
test_smoothstep_slope);
|
2016-02-06 16:46:19 +08:00
|
|
|
}
|