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 "globals.h"
6#include "bit_shifts.h"
7
8#ifdef USE_LIBDIVIDE
9// We use pre-computed constant parameters with libdivide where possible.
10// Using predefined constants saves flash and RAM (.bss) versus calling the
11// libdivide generator functions (E.g. libdivide_s32_gen)
12// 32-bit constants generated here: https://godbolt.org/z/vP8Kfejo9
13#include "src/libdivide/libdivide.h"
14#include "src/libdivide/constant_fast_div.h"
15#endif
16
18
36#define DIV_ROUND_DOWN -1
37
39#define DIV_ROUND_UP 1
40
46#define DIV_ROUND_NEAREST 0
47
49#define DIV_ROUND_BEHAVIOR DIV_ROUND_NEAREST
50// (Unit tests expect DIV_ROUND_NEAREST behavior)
51
59#define DIV_ROUND_CORRECT(d, t) ((t)(((d)>>1U)+(t)DIV_ROUND_BEHAVIOR))
61
76#define DIV_ROUND_CLOSEST(n, d, t) ( \
77 (((n) < (t)(0)) ^ ((d) < (t)(0))) ? \
78 ((t)((n) - DIV_ROUND_CORRECT(d, t))/(t)(d)) : \
79 ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d)))
80
93#define UDIV_ROUND_CLOSEST(n, d, t) ((t)((n) + DIV_ROUND_CORRECT(d, t))/(t)(d))
94
96
98#define IS_INTEGER(d) ((d) == (int32_t)(d))
99
109static inline uint16_t div100(uint16_t n) {
110 // As of avr-gcc 5.4.0, the compiler will optimize this to a multiply/shift
111 // (unlike the signed integer overload, where __divmodhi4 is still called
112 // see https://godbolt.org/z/c5bs5noT1)
113 return UDIV_ROUND_CLOSEST(n, UINT16_C(100), uint16_t);
114}
115
116static inline int16_t div100(int16_t n) {
117#ifdef USE_LIBDIVIDE
118 // Try faster unsigned path first
119 if (n>0) {
120 return div100((uint16_t)n);
121 }
122 // Negative values here, so adjust pre-division to get same
123 // behavior as roundf(float)
124 return libdivide::libdivide_s16_do_raw(n - DIV_ROUND_CORRECT(UINT16_C(100), uint16_t), S16_MAGIC(100), S16_MORE(100));
125#else
126 return DIV_ROUND_CLOSEST(n, UINT16_C(100), int16_t);
127#endif
128}
129
130static inline uint32_t div100(uint32_t n) {
131#ifdef USE_LIBDIVIDE
132 if (n<=(uint32_t)UINT16_MAX) {
133 return div100((uint16_t)n);
134 }
135 return libdivide::libdivide_u32_do_raw(n + DIV_ROUND_CORRECT(UINT32_C(100), uint32_t), 2748779070L, 6);
136#else
137 return UDIV_ROUND_CLOSEST(n, UINT32_C(100), uint32_t);
138#endif
139}
140
141#if defined(__arm__)
142static inline int div100(int n) {
143 return DIV_ROUND_CLOSEST(n, 100U, int);
144}
145#else
146static inline int32_t div100(int32_t n) {
147#ifdef USE_LIBDIVIDE
149 return div100((int16_t)n);
150 }
151 return libdivide::libdivide_s32_do_raw(n + (DIV_ROUND_CORRECT(UINT16_C(100), uint32_t) * (n<0 ? -1 : 1)), 1374389535L, 5);
152#else
153 return DIV_ROUND_CLOSEST(n, INT32_C(100), int32_t);
154#endif
155}
156#endif
158
165static inline uint32_t div360(uint32_t n) {
166#ifdef USE_LIBDIVIDE
167 return libdivide::libdivide_u32_do_raw(n + DIV_ROUND_CORRECT(UINT32_C(360), uint32_t), 1813430637L, 72);
168#else
170#endif
171}
172
184
185
195#ifdef USE_LIBDIVIDE
196 return (uint16_t)libdivide::libdivide_u32_do_raw(x200 + DIV_ROUND_CORRECT(UINT32_C(200), uint32_t), 2748779070L, 7);
197#else
199#endif
200}
201
212{
213 if (value<min) { return value + nudgeAmount; }
214 if (value>max) { return value - nudgeAmount; }
215 return value;
216}
217
218#if defined(CORE_AVR) || defined(ARDUINO_ARCH_AVR)
219
221 return divisor>(uint16_t)(dividend>>16U);
222}
223
224#endif
241{
242#if defined(CORE_AVR) || defined(ARDUINO_ARCH_AVR)
243
244 if (divisor==0U || !udiv_is16bit_result(dividend, divisor)) { return UINT16_MAX; }
245
246 #define INDEX_REG "r16"
247
248 asm(
249 " ldi " INDEX_REG ", 16 ; bits = 16\n\t"
250 "0:\n\t"
251 " lsl %A0 ; shift\n\t"
252 " rol %B0 ; rem:quot\n\t"
253 " rol %C0 ; left\n\t"
254 " rol %D0 ; by 1\n\t"
255 " brcs 1f ; if carry out, rem > divisor\n\t"
256 " cp %C0, %A1 ; is rem less\n\t"
257 " cpc %D0, %B1 ; than divisor ?\n\t"
258 " brcs 2f ; yes, when carry out\n\t"
259 "1:\n\t"
260 " sub %C0, %A1 ; compute\n\t"
261 " sbc %D0, %B1 ; rem -= divisor\n\t"
262 " ori %A0, 1 ; record quotient bit as 1\n\t"
263 "2:\n\t"
264 " dec " INDEX_REG " ; bits--\n\t"
265 " brne 0b ; until bits == 0"
266 : "=d" (dividend)
267 : "d" (divisor) , "0" (dividend)
268 : INDEX_REG
269 );
270
271 // Lower word contains the quotient, upper word contains the remainder.
272 return dividend & 0xFFFFU;
273#else
274 // The non-AVR platforms are all fast enough (or have built in hardware dividers)
275 // so just fall back to regular 32-bit division.
276 return dividend / divisor;
277#endif
278}
279
280
288{
289#if defined(CORE_AVR) || defined(ARDUINO_ARCH_AVR)
291 return udiv_32_16(dividend, divisor);
292#else
294#endif
295}
296
308template<class T>
309constexpr const T& clamp(const T& v, const T& lo, const T& hi){
310 return v<lo ? lo : hi<v ? hi : v;
311}
312
314
315template <typename T, typename TPrime>
316static inline T LOW_PASS_FILTER_8BIT(T input, uint8_t alpha, T prior) {
317 // Intermediate steps are for MISRA compliance
318 // Equivalent to: (input * (256 - alpha) + (prior * alpha)) >> 8
319 static constexpr T ALPHA_MAX = (T)256;
323 return (T)(preshift / ALPHA_MAX); // Division should resolve to a shift & avoids a MISRA violation
324}
325
327
342
347
348#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:349
#define DIV_ROUND_CORRECT(d, t)
Computes the denominator correction for rounding division based on our rounding behavior.
Definition maths.h:59
#define DIV_ROUND_CLOSEST(n, d, t)
Rounded integer division.
Definition maths.h:76
#define UDIV_ROUND_CLOSEST(n, d, t)
Rounded unsigned integer division.
Definition maths.h:93
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:339
static uint32_t div360(uint32_t n)
Optimised integer division by 360.
Definition maths.h:165
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:287
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:309
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:211
static uint16_t udiv_32_16(uint32_t dividend, uint16_t divisor)
Optimised division: uint32_t/uint16_t => uint16_t.
Definition maths.h:240
static uint32_t percentage(uint8_t percent, uint32_t value)
Integer based percentage calculation.
Definition maths.h:180
static uint16_t halfPercentage(uint8_t percent, uint16_t value)
Integer based half-percentage calculation.
Definition maths.h:193
static uint16_t div100(uint16_t n)
Performance optimised integer division by 100. I.e. same as n/100.
Definition maths.h:109