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
17extern uint8_t random1to100(void);
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//This is a dedicated function that specifically handles the case of mapping 0-1023 values into a 0 to X range
219//This is a common case because it means converting from a standard 10-bit analog input to a byte or 10-bit analog into 0-511 (Eg the temperature readings)
220#define fastMap1023toX(x, out_max) ( rshift<10>((uint32_t)(x) * (out_max)) )
221//This is a new version that allows for out_min
222#define fastMap10Bit(x, out_min, out_max) ( rshift<10>( (uint32_t)(x) * ((out_max)-(out_min)) ) + (out_min))
223
224#if defined(CORE_AVR) || defined(ARDUINO_ARCH_AVR)
225
227 return divisor>(uint16_t)(dividend>>16U);
228}
229
230#endif
247{
248#if defined(CORE_AVR) || defined(ARDUINO_ARCH_AVR)
249
250 if (divisor==0U || !udiv_is16bit_result(dividend, divisor)) { return UINT16_MAX; }
251
252 #define INDEX_REG "r16"
253
254 asm(
255 " ldi " INDEX_REG ", 16 ; bits = 16\n\t"
256 "0:\n\t"
257 " lsl %A0 ; shift\n\t"
258 " rol %B0 ; rem:quot\n\t"
259 " rol %C0 ; left\n\t"
260 " rol %D0 ; by 1\n\t"
261 " brcs 1f ; if carry out, rem > divisor\n\t"
262 " cp %C0, %A1 ; is rem less\n\t"
263 " cpc %D0, %B1 ; than divisor ?\n\t"
264 " brcs 2f ; yes, when carry out\n\t"
265 "1:\n\t"
266 " sub %C0, %A1 ; compute\n\t"
267 " sbc %D0, %B1 ; rem -= divisor\n\t"
268 " ori %A0, 1 ; record quotient bit as 1\n\t"
269 "2:\n\t"
270 " dec " INDEX_REG " ; bits--\n\t"
271 " brne 0b ; until bits == 0"
272 : "=d" (dividend)
273 : "d" (divisor) , "0" (dividend)
274 : INDEX_REG
275 );
276
277 // Lower word contains the quotient, upper word contains the remainder.
278 return dividend & 0xFFFFU;
279#else
280 // The non-AVR platforms are all fast enough (or have built in hardware dividers)
281 // so just fall back to regular 32-bit division.
282 return dividend / divisor;
283#endif
284}
285
286
294{
295#if defined(CORE_AVR) || defined(ARDUINO_ARCH_AVR)
297 return udiv_32_16(dividend, divisor);
298#else
300#endif
301}
302
303#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 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:293
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:246
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