smoothstep.c 2.7 KB

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