Speeduino
Loading...
Searching...
No Matches
maths.h
Go to the documentation of this file.
1#ifndef MATH_H
2#define MATH_H
3
4#include <stdint.h>
5#include "bit_shifts.h"
6
7#ifdef USE_LIBDIVIDE
8// We use pre-computed constant parameters with libdivide where possible.
9// Using predefined constants saves flash and RAM (.bss) versus calling the
10// libdivide generator functions (E.g. libdivide_s32_gen)
11// 32-bit constants generated here: https://godbolt.org/z/vP8Kfejo9
12#include "src/libdivide/libdivide.h"
13#include "src/libdivide/constant_fast_div.h"
14#endif
15
17
35#define DIV_ROUND_DOWN -1
36
38#define DIV_ROUND_UP 1
39
45#define DIV_ROUND_NEAREST 0
46
48#define DIV_ROUND_BEHAVIOR DIV_ROUND_NEAREST
49// (Unit tests expect DIV_ROUND_NEAREST behavior)
50
58#define DIV_ROUND_CORRECT(d, t) ((t)(((d)>>1U)+(t)DIV_ROUND_BEHAVIOR))
60
75#define DIV_ROUND_CLOSEST(n, d, t) ( \
76 (((n) < (t)(0)) ^ ((d) < (t)(0))) ? \
77 ((t)((n) - DIV_ROUND_CORRECT(d, t))/(t)(d)) : \
78 ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d)))
79
92#define UDIV_ROUND_CLOSEST(n, d, t) ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d))
93
101template <uint16_t divisor>
102static inline constexpr uint16_t div_round_closest_u16(uint16_t n) {
103 // This is a compile time version of UDIV_ROUND_CLOSEST
104 //
105 // As of avr-gcc 5.4.0, the compiler will optimize this to a multiply/shift
106 // assuming d is a constant.
108}
110
112#define IS_INTEGER(d) ((d) == (int32_t)(d))
113
123static inline uint16_t div100(uint16_t n) {
124 // As of avr-gcc 5.4.0, the compiler will optimize this to a multiply/shift
125 // (unlike the signed integer overload, where __divmodhi4 is still called
126 // see https://godbolt.org/z/c5bs5noT1)
127 return UDIV_ROUND_CLOSEST(n, UINT16_C(100), uint16_t);
128}
129
130static inline int16_t div100(int16_t n) {
131#ifdef USE_LIBDIVIDE
132 // Try faster unsigned path first
133 if (n>0) {
134 return div100((uint16_t)n);
135 }
136 // Negative values here, so adjust pre-division to get same
137 // behavior as roundf(float)
138 return libdivide::libdivide_s16_do_raw(n - DIV_ROUND_CORRECT(UINT16_C(100), uint16_t), S16_MAGIC(100), S16_MORE(100));
139#else
140 return DIV_ROUND_CLOSEST(n, UINT16_C(100), int16_t);
141#endif
142}
143
144static inline uint32_t div100(uint32_t n) {
145#ifdef USE_LIBDIVIDE
146 if (n<=(uint32_t)UINT16_MAX) {
147 return div100((uint16_t)n);
148 }
149 return libdivide::libdivide_u32_do_raw(n + DIV_ROUND_CORRECT(UINT32_C(100), uint32_t), 2748779070L, 6);
150#else
151 return UDIV_ROUND_CLOSEST(n, UINT32_C(100), uint32_t);
152#endif
153}
154
155#if defined(__arm__)
156static inline int div100(int n) {
157 return DIV_ROUND_CLOSEST(n, 100U, int);
158}
159#else
160static inline int32_t div100(int32_t n) {
161#ifdef USE_LIBDIVIDE
163 return div100((int16_t)n);
164 }
165 return libdivide::libdivide_s32_do_raw(n + (DIV_ROUND_CORRECT(UINT16_C(100), uint32_t) * (n<0 ? -1 : 1)), 1374389535L, 5);
166#else
167 return DIV_ROUND_CLOSEST(n, INT32_C(100), int32_t);
168#endif
169}
170#endif
172
179static inline uint32_t div360(uint32_t n) {
180#ifdef USE_LIBDIVIDE
181 return libdivide::libdivide_u32_do_raw(n + DIV_ROUND_CORRECT(UINT32_C(360), uint32_t), 1813430637L, 72);
182#else
184#endif
185}
186
198
199
209#ifdef USE_LIBDIVIDE
210 return (uint16_t)libdivide::libdivide_u32_do_raw(x200 + DIV_ROUND_CORRECT(UINT32_C(200), uint32_t), 2748779070L, 7);
211#else
213#endif
214}
215
226{
227 if (value<min) { return value + nudgeAmount; }
228 if (value>max) { return value - nudgeAmount; }
229 return value;
230}
231
232#if defined(__AVR__)
233
235 return divisor>(uint16_t)(dividend>>16U);
236}
237
238#endif
255{
256#if defined(__AVR__)
257
258 if (divisor==0U || !udiv_is16bit_result(dividend, divisor)) { return UINT16_MAX; }
259
260 #define INDEX_REG "r16"
261
262 asm(
263 " ldi " INDEX_REG ", 16 ; bits = 16\n\t"
264 "0:\n\t"
265 " lsl %A0 ; shift\n\t"
266 " rol %B0 ; rem:quot\n\t"
267 " rol %C0 ; left\n\t"
268 " rol %D0 ; by 1\n\t"
269 " brcs 1f ; if carry out, rem > divisor\n\t"
270 " cp %C0, %A1 ; is rem less\n\t"
271 " cpc %D0, %B1 ; than divisor ?\n\t"
272 " brcs 2f ; yes, when carry out\n\t"
273 "1:\n\t"
274 " sub %C0, %A1 ; compute\n\t"
275 " sbc %D0, %B1 ; rem -= divisor\n\t"
276 " ori %A0, 1 ; record quotient bit as 1\n\t"
277 "2:\n\t"
278 " dec " INDEX_REG " ; bits--\n\t"
279 " brne 0b ; until bits == 0"
280 : "=d" (dividend)
281 : "d" (divisor) , "0" (dividend)
282 : INDEX_REG
283 );
284
285 // Lower word contains the quotient, upper word contains the remainder.
286 return dividend & 0xFFFFU;
287#else
288 // The non-AVR platforms are all fast enough (or have built in hardware dividers)
289 // so just fall back to regular 32-bit division.
290 return dividend / divisor;
291#endif
292}
293
294
302{
303#if defined(__AVR__)
305 return udiv_32_16(dividend, divisor);
306#else
308#endif
309}
310
322template<class T>
323constexpr const T& clamp(const T& v, const T& lo, const T& hi){
324 return v<lo ? lo : hi<v ? hi : v;
325}
326
328
329template <typename T, typename TPrime>
330static inline T LOW_PASS_FILTER_8BIT(T input, uint8_t alpha, T prior) {
331 // Intermediate steps are for MISRA compliance
332 // Equivalent to: (input * (256 - alpha) + (prior * alpha)) >> 8
333 static constexpr T ALPHA_MAX = (T)256;
337 return (T)(preshift / ALPHA_MAX); // Division should resolve to a shift & avoids a MISRA violation
338}
339
341
356
361
373static inline uint8_t scale(const uint8_t from, const uint8_t fromRange, const uint8_t toRange) {
374 // Using uint16_t to avoid overflow when calculating the result
376}
377
391static 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) {
392 // Stick to unsigned math for performance, so need to check for output range inversion
393 if (toLow>toHigh) {
395 } else {
397 }
398}
399
400#endif
Optimized multi-byte bit shifting for AVR-GCC only. See Optimised bitwise shifts.
static uint32_t rshift(uint32_t a)
Bitwise right shift - generic, unoptimized, case.
Definition bit_shifts.h:348
#define DIV_ROUND_CORRECT(d, t)
Computes the denominator correction for rounding division based on our rounding behavior.
Definition maths.h:58
static constexpr uint16_t div_round_closest_u16(uint16_t n)
Rounded unsigned integer division optimized for compile time constants.
Definition maths.h:102
#define DIV_ROUND_CLOSEST(n, d, t)
Rounded integer division.
Definition maths.h:75
#define UDIV_ROUND_CLOSEST(n, d, t)
Rounded unsigned integer division.
Definition maths.h:92
uint8_t random1to100(void)
Definition maths.cpp:8
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:353
static uint32_t div360(uint32_t n)
Optimised integer division by 360.
Definition maths.h:179
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:373
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:391
static uint16_t udiv_32_16_closest(uint32_t dividend, uint16_t divisor)
Same as udiv_32_16(), except this will round to nearest integer instead of truncating.
Definition maths.h:301
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:323
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:225
static uint16_t udiv_32_16(uint32_t dividend, uint16_t divisor)
Optimised division: uint32_t/uint16_t => uint16_t.
Definition maths.h:254
static uint32_t percentage(uint8_t percent, uint32_t value)
Integer based percentage calculation.
Definition maths.h:194
static uint16_t halfPercentage(uint8_t percent, uint16_t value)
Integer based half-percentage calculation.
Definition maths.h:207
static uint16_t div100(uint16_t n)
Performance optimised integer division by 100. I.e. same as n/100.
Definition maths.h:123