6#include <avr-fast-shift.h>
7#include <avr-fast-div.h>
51#define DIV_ROUND_DOWN -1
61#define DIV_ROUND_NEAREST 0
64#define DIV_ROUND_BEHAVIOR DIV_ROUND_NEAREST
74#define DIV_ROUND_CORRECT(d, t) ((t)(((d)>>1U)+(t)DIV_ROUND_BEHAVIOR))
91#define DIV_ROUND_CLOSEST(n, d, t) ( \
92 (((n) < (t)(0)) ^ ((d) < (t)(0))) ? \
93 ((t)((n) - DIV_ROUND_CORRECT(d, t))/(t)(d)) : \
94 ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d)))
108#define UDIV_ROUND_CLOSEST(n, d, t) ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d))
117template <u
int16_t divisor>
127#define UDIV_ROUND_UP(n, d, t) ((t)((n) + (t)((d)+1U))/(t)(d))
132#define IS_INTEGER(d) ((d) == (int32_t)(d))
143static inline uint16_t
div100(uint16_t n) {
148 constexpr libdivide::libdivide_u16_t libdiv_u16_100 = { .magic = 18351, .more = 70 };
150 return libdivide::libdivide_u16_do_raw(n +
DIV_ROUND_CORRECT(UINT16_C(100), uint16_t), libdiv_u16_100.magic, libdiv_u16_100.more);
161 return div100((uint16_t)n);
165 constexpr libdivide::libdivide_s16_t libdiv_s16_100 = { .magic = 20972, .more = 5 };
167 return libdivide::libdivide_s16_do_raw(n -
DIV_ROUND_CORRECT(UINT16_C(100), uint16_t), libdiv_s16_100.magic, libdiv_s16_100.more);
174static inline uint32_t
div100(uint32_t n) {
176 if (n<=(uint32_t)UINT16_MAX) {
177 return div100((uint16_t)n);
179 constexpr libdivide::libdivide_u32_t libdiv_u32_100 = { .magic = 2748779070, .more = 6 };
181 return libdivide::libdivide_u32_do_raw(n +
DIV_ROUND_CORRECT(UINT32_C(100), uint32_t), libdiv_u32_100.magic, libdiv_u32_100.more);
190 if (n<=INT16_MAX && n>=INT16_MIN) {
191 return div100((int16_t)n);
193 constexpr libdivide::libdivide_s32_t libdiv_s32_100 = { .magic = 1374389535, .more = 5 };
195 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);
209static inline uint32_t
div360(uint32_t n) {
211 constexpr libdivide::libdivide_u32_t libdiv_u32_360 = { .magic = 1813430637, .more = 72 };
213 return libdivide::libdivide_u32_do_raw(n +
DIV_ROUND_CORRECT(UINT32_C(360), uint32_t), libdiv_u32_360.magic, libdiv_u32_360.more);
234 constexpr uint8_t CORRECTION_SHIFT = b-1U;
235 constexpr uint32_t CORRECTION = 1UL<<CORRECTION_SHIFT;
236 return rshift<b>((uint32_t)(
a+CORRECTION));
245template <u
int8_t bitsPrecision>
246static inline uint32_t _percentageApprox(uint16_t percent, uint32_t value) {
247 uint16_t iPercent =
div100((uint16_t)(percent << bitsPrecision));
248 return rshift_round<bitsPrecision>(value * (uint32_t)iPercent);
279 #define TEST_AND_APPLY(precision) \
280 if (percent<(UINT16_C(1)<<(UINT16_C(16)-(precision)))) { \
281 return _percentageApprox<(precision)>(percent, value); \
289 #undef TEST_AND_APPLY
292 return _percentageApprox<5U>(percent, value);
299 if (percent<(UINT8_C(1)<<UINT8_C(7))) {
300 return _percentageApprox<9U>(percent, value);
302 return _percentageApprox<8U>(percent, value);
318static inline uint32_t
percentage(uint16_t percent, uint32_t value)
320 return (uint32_t)
div100((uint32_t)value * (uint32_t)percent);
332 uint32_t x200 = (uint32_t)percent * (uint32_t)value;
334 constexpr libdivide::libdivide_u32_t libdiv_u32_200 = { .magic = 2748779070, .more = 7 };
336 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 T
nudge(T min, T max, T value)
353 T nudgeAmount = max - min;
354 if (value<min) {
return value + nudgeAmount; }
355 if (value>=max) {
return value - nudgeAmount; }
389template <
typename TDiv
idend,
typename TDivisor>
408 return v<lo ? lo : hi<v ? hi : v;
414template <
typename T,
typename TPrime>
415static inline T LOW_PASS_FILTER_8BIT(T input, uint8_t alpha, T prior) {
418 static constexpr uint16_t ALPHA_MAX_SHIFT = 8U;
419 static constexpr uint16_t ALPHA_MAX = 2U << (ALPHA_MAX_SHIFT-1U);
420 uint16_t inv_alpha = ALPHA_MAX - alpha;
421 TPrime prior_alpha = (prior * (TPrime)alpha);
422 TPrime preshift = (input * (TPrime)inv_alpha) + prior_alpha;
423 return (T)(preshift >> (TPrime)ALPHA_MAX_SHIFT);
439static inline uint16_t
LOW_PASS_FILTER(uint16_t input, uint8_t alpha, uint16_t prior) {
440 return LOW_PASS_FILTER_8BIT<uint16_t, uint32_t>(input, alpha, prior);
445 return LOW_PASS_FILTER_8BIT<int16_t, int32_t>(input, alpha, prior);
459static inline uint8_t
scale(
const uint8_t from,
const uint8_t fromRange,
const uint8_t toRange) {
461 return fromRange==0U ? 0U : (((uint16_t)from * (uint16_t)toRange) / (uint16_t)fromRange);
477static 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) {
480 return toLow -
scale(from - fromLow, fromHigh - fromLow, toLow-toHigh);
482 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:74
TESTABLE_STATIC_CONSTEXPR uint16_t div_round_closest_u16(uint16_t n)
Rounded unsigned integer division optimized for compile time constants.
Definition maths.h:118
#define DIV_ROUND_CLOSEST(n, d, t)
Rounded integer division.
Definition maths.h:91
#define UDIV_ROUND_CLOSEST(n, d, t)
Rounded unsigned integer division.
Definition maths.h:108
static uint8_t a
Definition maths.cpp:10
uint8_t random1to100(void) noexcept
Definition maths.cpp:11
static constexpr uint32_t MICROS_PER_MIN
Self-explanatory.
Definition maths.h:23
static T normalize(T min, T max, T value)
Correct value into the range [ min, max ) by adding or subtracting ( max- min )
Definition maths.h:369
static constexpr uint32_t MICROS_PER_SEC
Self-explanatory.
Definition maths.h:20
#define TEST_AND_APPLY(precision)
static constexpr uint32_t MILLI_PER_SEC
Self-explanatory.
Definition maths.h:29
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:439
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:390
static constexpr uint32_t MICROS_PER_HOUR
Self-explanatory.
Definition maths.h:26
uint16_t pwmFreqToTicks(uint16_t frequency)
Convert a frequency in Hz to the equivalent number of PWM timer ticks.
Definition maths.cpp:34
static uint32_t percentage(uint16_t percent, uint32_t value)
Integer based percentage calculation.
Definition maths.h:318
static uint32_t div360(uint32_t n)
Optimised integer division by 360.
Definition maths.h:209
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:459
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:477
static uint32_t percentageApprox(uint16_t percent, uint32_t value)
Integer based percentage calculation: faster, but less accurate, than percentage()
Definition maths.h:272
static constexpr uint8_t ONE_HUNDRED_PCT
This is only here to eliminate magic numbers.
Definition maths.h:310
static uint32_t rshift_round(uint32_t a)
Rounded arithmetic right shift.
Definition maths.h:233
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:407
static uint16_t halfPercentage(uint8_t percent, uint16_t value)
Integer based half-percentage calculation.
Definition maths.h:331
static T nudge(T min, T max, T value)
Make **one* pass at correcting the value into the range [ min, max)
Definition maths.h:351
static uint16_t div100(uint16_t n)
Performance optimised integer division by 100. I.e. same as n/100.
Definition maths.h:143
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