Plaquette
 
Loading...
Searching...
No Matches
pq_math.h
1/*
2 * pq_math.h
3 *
4 * Mathematical functions - replacements of Arduino macros.
5 *
6 * Arduino’s min/max/abs/etc. are unsafe macros: they re-evaluate arguments,
7 * lack type safety, and collide with <algorithm>/<cmath>. This header provides
8 * constexpr function alternatives in namespace pq (min, max, abs, constrain,
9 * round, radians, degrees, sq). Legacy macro names are redefined to call the
10 * safe pq:: functions for backwards compatibility.
11 *
12 * (c) 2025 Sofian Audry :: info(@)sofianaudry(.)com
13 *
14 * This program is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 */
27#ifndef PQ_MATH_H_
28#define PQ_MATH_H_
29
30#include <Arduino.h>
31
32// --- Neutralize Arduino's macros so they don't collide ---
33#ifdef min
34# undef min
35#endif
36#ifdef max
37# undef max
38#endif
39#ifdef abs
40# undef abs
41#endif
42#ifdef constrain
43# undef constrain
44#endif
45#ifdef round
46# undef round
47#endif
48#ifdef radians
49# undef radians
50#endif
51#ifdef degrees
52# undef degrees
53#endif
54#ifdef sq
55# undef sq
56#endif
57
58namespace pq {
59
60// --- Common type machinery ---------------------------------
61// Ensures math functions work safely when mixing types (e.g. int and float).
62#if defined(__has_include) && __has_include(<type_traits>)
63
64#include <type_traits>
65template <typename A, typename B>
66 using common_pair_t = typename std::common_type<A,B>::type;
67
68template <typename A, typename B, typename C>
69 using common_triple_t = typename std::common_type<A,B,C>::type;
70
71#else
72
73// Minimal fallback: works for most arithmetic types
74template <typename A, typename B>
76 using type = decltype(true ? A{} : B{});
77 };
78template <typename A, typename B>
79 using common_pair_t = typename common_pair_type<A,B>::type;
80
81template <typename A, typename B, typename C>
83 using type = decltype(true ? true ? A{} : B{} : C{});
84 };
85template <typename A, typename B, typename C>
86 using common_triple_t = typename common_triple_type<A,B,C>::type;
87
88#endif
89
90// --- Math functions ---------------------------------------
91
92// -------- min / max --------
93template <class A, class B>
94constexpr common_pair_t<A,B> min(A a, B b) {
95 typedef common_pair_t<A,B> R;
96 return (static_cast<R>(a) < static_cast<R>(b)) ?
97 static_cast<R>(a) :
98 static_cast<R>(b);
99}
100
101template <class A, class B>
102constexpr common_pair_t<A,B> max(A a, B b) {
103 typedef common_pair_t<A,B> R;
104 return (static_cast<R>(a) > static_cast<R>(b)) ?
105 static_cast<R>(a) :
106 static_cast<R>(b);
107}
108
109// -------- abs --------
110template <typename T>
111constexpr T abs(T x) {
112 return (x < T{0}) ? -x : x;
113}
114
115
116// -------- constrain --------
117template <class A, class L, class H>
118constexpr common_triple_t<A,L,H>
119constrain(A amt, L low, H high) {
120 typedef common_triple_t<A,L,H> R;
121 return (static_cast<R>(amt) < static_cast<R>(low) ? static_cast<R>(low) :
122 static_cast<R>(amt) > static_cast<R>(high) ? static_cast<R>(high) :
123 static_cast<R>(amt));
124}
125
126// -------- round (Arduino semantics: return long) --------
127template <typename Float>
128constexpr long round(Float x) {
129 return (x >= Float{0})
130 ? static_cast<long>(x + Float{0.5})
131 : static_cast<long>(x - Float{0.5});
132}
133
134// -------- radians / degrees --------
135template <typename T>
136constexpr double radians(T deg) {
137 return deg * DEG_TO_RAD;
138}
139
140template <typename T>
141constexpr double degrees(T rad) {
142 return rad * RAD_TO_DEG;
143}
144
145// -------- sq --------
146template <typename T>
147constexpr T sq(T x) { return x * x; }
148
149} // namespace pq
150
151// --- Legacy Arduino names for backwards compatibility -----
152#define min(a,b) (::pq::min((a),(b)))
153#define max(a,b) (::pq::max((a),(b)))
154#define abs(x) (::pq::abs((x)))
155#define constrain(x,l,h) (::pq::constrain((x),(l),(h)))
156#define round(x) (::pq::round((x)))
157#define radians(d) (::pq::radians((d)))
158#define degrees(r) (::pq::degrees((r)))
159#define sq(x) (::pq::sq((x)))
160
161#endif
Definition pq_math.h:75
Definition pq_math.h:82