tepples

C log2 behavior test

Oct 24th, 2021
1,116
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2. log2 behavior tester
  3. copyright 2021 Damian Yerrick
  4. insert GNU All-Permissive License here
  5.  
  6. build and run:
  7. gcc -Wall -Wextra -Og -fsanitize=undefined log2test.c -lm -o log2test && log2test | less
  8.  
  9. Notice how the inaccuracy creeps in at 25 bits for cast to float
  10. or 49 bits for cast to double.
  11.  
  12. */
  13.  
  14. #include <stdio.h>
  15. #include <inttypes.h>  // same as stdint.h plus
  16. #include <math.h>
  17.  
  18. /**
  19.  * calculates floor(log[2](i)), or -1 if i < 1
  20.  * but can a compiler recognize it and convert it to clz?
  21.  */
  22. signed log2ul (uint_fast32_t x) {
  23.   signed result = 0;
  24.   if (x < 3) return x - 1;  // 0->-1, 1->0, 2->1
  25.   while (x > 1 << 16) { result += 16; x >>= 16; }
  26.   while (x > 1 <<  4) { result +=  4; x >>=  4; }
  27.   while (x > 1      ) { result +=  1; x >>=  1; }
  28.   return result;
  29. }
  30.  
  31. /**
  32.  * calculates floor(log[2](i)), or -1 if i < 1
  33.  * but can a compiler recognize it and convert it to clz?
  34.  */
  35. signed log2ull (unsigned long long x) {
  36.   signed result = 0;
  37.   if (x < 3) return x - 1;  // 0->-1, 1->0, 2->1
  38.   while (x > 1 << 16) { result += 16; x >>= 16; }
  39.   while (x > 1 <<  4) { result +=  4; x >>=  4; }
  40.   while (x > 1      ) { result +=  1; x >>=  1; }
  41.   return result;
  42. }
  43.  
  44. void u32_trial(unsigned shiftamt) {
  45.   uint32_t arg = (uint32_t)1 << (shiftamt - 1);  // e.g. 8->128
  46.   arg = (arg - 1) * 2;  // e.g. 8->254
  47.   printf("trial for log2(1 << %u) using uint32_t\n",
  48.          shiftamt);
  49.   for (unsigned b = 5; b > 0 && arg > 0; --b, ++arg) {
  50.     signed loop_result = log2ul(arg);
  51.     double float_result = log2((float)arg);
  52.     signed floor_float = floor(float_result);
  53.     double double_result = log2((double)arg);
  54.     signed floor_double = floor(double_result);
  55.     printf("log2(%10"PRIu32") = %2d int, %7.4f=>%2d float, %7.4f=>%2d double\n",
  56.            arg, loop_result, float_result, floor_float,
  57.            double_result, floor_double);
  58.   }
  59. }
  60.  
  61. void u64_trial(unsigned shiftamt) {
  62.   uint64_t arg = (uint64_t)1 << (shiftamt - 1);  // e.g. 8->128
  63.   arg = (arg - 1) * 2;  // e.g. 8->254
  64.   printf("trial for log2(1 << %u) using uint64_t\n",
  65.          shiftamt);
  66.   for (unsigned b = 5; b > 0 && arg > 0; --b, ++arg) {
  67.     signed loop_result = log2ul(arg);
  68.     double float_result = log2((float)arg);
  69.     signed floor_float = floor(float_result);
  70.     double double_result = log2((double)arg);
  71.     signed floor_double = floor(double_result);
  72.     printf("log2(%10"PRIu64") = %2d int, %7.4f=>%2d float, %7.4f=>%2d double\n",
  73.            arg, loop_result, float_result, floor_float,
  74.            double_result, floor_double);
  75.   }
  76. }
  77.  
  78. int main(void) {
  79.   for (unsigned i = 4; i <= 32; ++i) u32_trial(i);
  80.   for (unsigned i = 4; i <= 64; ++i) u64_trial(i);
  81.   return 0;
  82. }
  83.  
RAW Paste Data