5#include <avr-fast-shift.h>
6#include <avr-fast-div.h>
50#define DIV_ROUND_DOWN -1
60#define DIV_ROUND_NEAREST 0
63#define DIV_ROUND_BEHAVIOR DIV_ROUND_NEAREST
73#define DIV_ROUND_CORRECT(d, t) ((t)(((d)>>1U)+(t)DIV_ROUND_BEHAVIOR))
90#define DIV_ROUND_CLOSEST(n, d, t) ( \
91 (((n) < (t)(0)) ^ ((d) < (t)(0))) ? \
92 ((t)((n) - DIV_ROUND_CORRECT(d, t))/(t)(d)) : \
93 ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d)))
107#define UDIV_ROUND_CLOSEST(n, d, t) ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d))
116template <u
int16_t divisor>
126#define UDIV_ROUND_UP(n, d, t) ((t)((n) + (t)((d)+1U))/(t)(d))
131#define IS_INTEGER(d) ((d) == (int32_t)(d))
142static inline uint16_t
div100(uint16_t n) {
147 constexpr libdivide::libdivide_u16_t libdiv_u16_100 = { .magic = 18351, .more = 70 };
149 return libdivide::libdivide_u16_do_raw(n +
DIV_ROUND_CORRECT(UINT16_C(100), uint16_t), libdiv_u16_100.magic, libdiv_u16_100.more);
160 return div100((uint16_t)n);
164 constexpr libdivide::libdivide_s16_t libdiv_s16_100 = { .magic = 20972, .more = 5 };
166 return libdivide::libdivide_s16_do_raw(n -
DIV_ROUND_CORRECT(UINT16_C(100), uint16_t), libdiv_s16_100.magic, libdiv_s16_100.more);
173static inline uint32_t
div100(uint32_t n) {
175 if (n<=(uint32_t)UINT16_MAX) {
176 return div100((uint16_t)n);
178 constexpr libdivide::libdivide_u32_t libdiv_u32_100 = { .magic = 2748779070, .more = 6 };
180 return libdivide::libdivide_u32_do_raw(n +
DIV_ROUND_CORRECT(UINT32_C(100), uint32_t), libdiv_u32_100.magic, libdiv_u32_100.more);
189 if (n<=INT16_MAX && n>=INT16_MIN) {
190 return div100((int16_t)n);
192 constexpr libdivide::libdivide_s32_t libdiv_s32_100 = { .magic = 1374389535, .more = 5 };
194 return libdivide::libdivide_s32_do_raw(n + (
DIV_ROUND_CORRECT(UINT16_C(100), uint32_t) * (n<0 ? -1 : 1)), libdiv_s32_100.magic, libdiv_s32_100.more);
208static inline uint32_t
div360(uint32_t n) {
210 constexpr libdivide::libdivide_u32_t libdiv_u32_360 = { .magic = 1813430637, .more = 72 };
212 return libdivide::libdivide_u32_do_raw(n +
DIV_ROUND_CORRECT(UINT32_C(360), uint32_t), libdiv_u32_360.magic, libdiv_u32_360.more);
233 constexpr uint8_t CORRECTION_SHIFT = b-1U;
234 constexpr uint32_t CORRECTION = 1UL<<CORRECTION_SHIFT;
235 return rshift<b>((uint32_t)(
a+CORRECTION));
244template <u
int8_t bitsPrecision>
245static inline uint32_t _percentageApprox(uint16_t percent, uint32_t value) {
246 uint16_t iPercent =
div100((uint16_t)(percent << bitsPrecision));
247 return rshift_round<bitsPrecision>(value * (uint32_t)iPercent);
278 #define TEST_AND_APPLY(precision) \
279 if (percent<(UINT16_C(1)<<(UINT16_C(16)-(precision)))) { \
280 return _percentageApprox<(precision)>(percent, value); \
288 #undef TEST_AND_APPLY
291 return _percentageApprox<5U>(percent, value);
298 if (percent<(UINT8_C(1)<<UINT8_C(7))) {
299 return _percentageApprox<9U>(percent, value);
301 return _percentageApprox<8U>(percent, value);
317static inline uint32_t
percentage(uint16_t percent, uint32_t value)
319 return (uint32_t)
div100((uint32_t)value * (uint32_t)percent);
331 uint32_t x200 = (uint32_t)percent * (uint32_t)value;
333 constexpr libdivide::libdivide_u32_t libdiv_u32_200 = { .magic = 2748779070, .more = 7 };
335 return (uint16_t)libdivide::libdivide_u32_do_raw(x200 +
DIV_ROUND_CORRECT(UINT32_C(200), uint32_t), libdiv_u32_200.magic, libdiv_u32_200.more);
351static inline int16_t
nudge(int16_t
min, int16_t
max, int16_t value, int16_t nudgeAmount)
353 if (value<
min) {
return value + nudgeAmount; }
354 if (value>
max) {
return value - nudgeAmount; }
364template <
typename TDiv
idend,
typename TDivisor>
383 return v<lo ? lo : hi<v ? hi : v;
389template <
typename T,
typename TPrime>
390static inline T LOW_PASS_FILTER_8BIT(T input, uint8_t alpha, T prior) {
393 static constexpr uint16_t ALPHA_MAX_SHIFT = 8U;
394 static constexpr uint16_t ALPHA_MAX = 2U << (ALPHA_MAX_SHIFT-1U);
395 uint16_t inv_alpha = ALPHA_MAX - alpha;
396 TPrime prior_alpha = (prior * (TPrime)alpha);
397 TPrime preshift = (input * (TPrime)inv_alpha) + prior_alpha;
398 return (T)(preshift >> (TPrime)ALPHA_MAX_SHIFT);
414static inline uint16_t
LOW_PASS_FILTER(uint16_t input, uint8_t alpha, uint16_t prior) {
415 return LOW_PASS_FILTER_8BIT<uint16_t, uint32_t>(input, alpha, prior);
420 return LOW_PASS_FILTER_8BIT<int16_t, int32_t>(input, alpha, prior);
434static inline uint8_t
scale(
const uint8_t from,
const uint8_t fromRange,
const uint8_t toRange) {
436 return fromRange==0U ? 0U : (((uint16_t)from * (uint16_t)toRange) / (uint16_t)fromRange);
452static inline uint8_t
fast_map(
const uint8_t from,
const uint8_t fromLow,
const uint8_t fromHigh,
const uint8_t toLow,
const uint8_t toHigh) {
455 return toLow -
scale(from - fromLow, fromHigh - fromLow, toLow-toHigh);
457 return scale(from - fromLow, fromHigh - fromLow, toHigh-toLow) + toLow;
#define DIV_ROUND_CORRECT(d, t)
Computes the denominator correction for rounding division based on our rounding behavior.
Definition maths.h:73
TESTABLE_STATIC_CONSTEXPR uint16_t div_round_closest_u16(uint16_t n)
Rounded unsigned integer division optimized for compile time constants.
Definition maths.h:117
#define DIV_ROUND_CLOSEST(n, d, t)
Rounded integer division.
Definition maths.h:90
#define UDIV_ROUND_CLOSEST(n, d, t)
Rounded unsigned integer division.
Definition maths.h:107
static uint8_t a
Definition maths.cpp:9
uint8_t random1to100(void) noexcept
Definition maths.cpp:10
static constexpr uint32_t MICROS_PER_MIN
Self-explanatory.
Definition maths.h:22
static constexpr uint32_t MICROS_PER_SEC
Self-explanatory.
Definition maths.h:19
#define TEST_AND_APPLY(precision)
static constexpr uint32_t MILLI_PER_SEC
Self-explanatory.
Definition maths.h:28
static uint16_t LOW_PASS_FILTER(uint16_t input, uint8_t alpha, uint16_t prior)
Simple low pass IIR filter 16-bit values.
Definition maths.h:414
TESTABLE_STATIC_CONSTEXPR TDividend fast_div_closest(TDividend dividend, TDivisor divisor)
Same as fast_div(), except this will round to nearest integer instead of truncating.
Definition maths.h:365
static constexpr uint32_t MICROS_PER_HOUR
Self-explanatory.
Definition maths.h:25
uint16_t pwmFreqToTicks(uint16_t frequency)
Convert a frequency in Hz to the equivalent number of PWM timer ticks.
Definition maths.cpp:33
static uint32_t percentage(uint16_t percent, uint32_t value)
Integer based percentage calculation.
Definition maths.h:317
static uint32_t div360(uint32_t n)
Optimised integer division by 360.
Definition maths.h:208
static uint8_t scale(const uint8_t from, const uint8_t fromRange, const uint8_t toRange)
Scale a value from one range to another.
Definition maths.h:434
static uint8_t fast_map(const uint8_t from, const uint8_t fromLow, const uint8_t fromHigh, const uint8_t toLow, const uint8_t toHigh)
Specialist version of map(long, long, long, long, long) for performance.
Definition maths.h:452
static uint32_t percentageApprox(uint16_t percent, uint32_t value)
Integer based percentage calculation: faster, but less accurate, than percentage()
Definition maths.h:271
static constexpr uint8_t ONE_HUNDRED_PCT
This is only here to eliminate magic numbers.
Definition maths.h:309
static uint32_t rshift_round(uint32_t a)
Rounded arithmetic right shift.
Definition maths.h:232
TESTABLE_STATIC_CONSTEXPR const T & clamp(const T &v, const T &lo, const T &hi)
clamps a given value between the minimum and maximum thresholds.
Definition maths.h:382
static int16_t nudge(int16_t min, int16_t max, int16_t value, int16_t nudgeAmount)
Make one pass at correcting the value into the range [min, max)
Definition maths.h:351
static uint16_t halfPercentage(uint8_t percent, uint16_t value)
Integer based half-percentage calculation.
Definition maths.h:330
static uint16_t div100(uint16_t n)
Performance optimised integer division by 100. I.e. same as n/100.
Definition maths.h:142
constexpr const _Tp & max(const _Tp &__a, const _Tp &__b)
Definition minmax.h:16
constexpr const _Tp & min(const _Tp &__a, const _Tp &__b)
Definition minmax.h:29
Unit testability support.
#define TESTABLE_STATIC_CONSTEXPR
Mark a function with constexpr, unless a unit test is in progress - then the entity is inlined.
Definition unit_testing.h:56