Add preprocessor math.

For now this is a square root function which should solve entirely
in the preprocessor. Test results described in the file.

Test code for runtime results, inserted right before the main loop
in mendel.c:

  for (uint32_t i = 0; i < 10000000; i++) {
    uint32_t mathlib = (uint32_t)(sqrt(i) + .5);
    uint32_t preprocessor = (uint32_t)(SQRT(i) + .5);

    if (mathlib != preprocessor) {
      sersendf_P(PSTR("%lu: %lu %lu\n"), i, mathlib, preprocessor);
      break;
    }

    if ((i & 0x00001fff) == 0)
      sersendf_P(PSTR("%lu\n"), i);
  }
  sersendf_P(PSTR("Square root check done.\n"));

Test code for compile time results:

  sersendf_P(PSTR("10000000: %lu\n"), (uint32_t)SQRT(10000000));
  sersendf_P(PSTR("10000000: %lu\n"), (uint32_t)sqrt(10000000));
  sersendf_P(PSTR("20000000: %lu\n"), (uint32_t)SQRT(20000000));
  sersendf_P(PSTR("20000000: %lu\n"), (uint32_t)sqrt(20000000));
  sersendf_P(PSTR("30000000: %lu\n"), (uint32_t)SQRT(30000000));
  sersendf_P(PSTR("30000000: %lu\n"), (uint32_t)sqrt(30000000));
  sersendf_P(PSTR("40000000: %lu\n"), (uint32_t)SQRT(40000000));
  sersendf_P(PSTR("40000000: %lu\n"), (uint32_t)sqrt(40000000));
  sersendf_P(PSTR("50000000: %lu\n"), (uint32_t)SQRT(50000000));
  sersendf_P(PSTR("50000000: %lu\n"), (uint32_t)sqrt(50000000));
  sersendf_P(PSTR("60000000: %lu\n"), (uint32_t)SQRT(60000000));
  sersendf_P(PSTR("60000000: %lu\n"), (uint32_t)sqrt(60000000));
  sersendf_P(PSTR("70000000: %lu\n"), (uint32_t)SQRT(70000000));
  sersendf_P(PSTR("70000000: %lu\n"), (uint32_t)sqrt(70000000));
  sersendf_P(PSTR("80000000: %lu\n"), (uint32_t)SQRT(80000000));
  sersendf_P(PSTR("80000000: %lu\n"), (uint32_t)sqrt(80000000));
  sersendf_P(PSTR("90000000: %lu\n"), (uint32_t)SQRT(90000000));
  sersendf_P(PSTR("90000000: %lu\n"), (uint32_t)sqrt(90000000));
This commit is contained in:
Markus Hitter 2014-07-06 17:04:24 +02:00
parent 76bf5ef75a
commit 6f83519a1d
1 changed files with 51 additions and 0 deletions

51
preprocessor_math.h Normal file
View File

@ -0,0 +1,51 @@
/** \file
\brief Math functions meant to be calculated in the C preprocessor.
\details Math functions presented here avoid library calls, which means they
can be solved at compile time and as such used to initialise
constants. When used for intitialising, their cost at runtime is
zero, as they resolve into a single number.
*/
#ifndef _PREPROCESSOR_MATH_H
#define _PREPROCESSOR_MATH_H
/*! Preprocessor square root.
(uint32_t)(SQRT(i) + .5)
equals
(uint32_t)(sqrt(i) + .5)
These two provide identical results up to 1'861'860 (tested at runtime) and
up to 10'000'000 at compile time. At 90'000'000, deviation is about 5%,
increasing further at even higher numbers. This "+ .5" is for rounding and
not crucial. Casting to other sizes is also possible.
Can be used for calculations at runtime, too, where it costs 944(!) bytes
binary size and takes roughly 10'000(!) clock cycles.
Initial version found on pl.comp.lang.c, posted by Jean-Louis PATANE.
*/
#define SQR00(x) (((double)(x)) / 2)
#define SQR01(x) ((SQR00(x) + ((x) / SQR00(x))) / 2)
#define SQR02(x) ((SQR01(x) + ((x) / SQR01(x))) / 2)
#define SQR03(x) ((SQR02(x) + ((x) / SQR02(x))) / 2)
#define SQR04(x) ((SQR03(x) + ((x) / SQR03(x))) / 2)
#define SQR05(x) ((SQR04(x) + ((x) / SQR04(x))) / 2)
#define SQR06(x) ((SQR05(x) + ((x) / SQR05(x))) / 2)
#define SQR07(x) ((SQR06(x) + ((x) / SQR06(x))) / 2)
#define SQR08(x) ((SQR07(x) + ((x) / SQR07(x))) / 2)
#define SQR09(x) ((SQR08(x) + ((x) / SQR08(x))) / 2)
#define SQR10(x) ((SQR09(x) + ((x) / SQR09(x))) / 2)
#define SQR11(x) ((SQR10(x) + ((x) / SQR10(x))) / 2)
#define SQR12(x) ((SQR11(x) + ((x) / SQR11(x))) / 2)
// You can add more of these lines here, each additional line increases
// accurate range by about factor 2 and costs additional 40 bytes binary size
// in the non-constant case. But beware, the length of the preprocessed term
// explodes, leading to several seconds compile time above about SQR13.
#define SQRT(x) ((SQR12(x) + ((x) / SQR12(x))) / 2)
#endif /* _PREPROCESSOR_MATH_H */