Scanframe Modular Application 0.1.0
Loading...
Searching...
No Matches
misc/gen/math.h
Go to the documentation of this file.
1#pragma once
2#include <array>
3#include <cmath>
4#include <misc/global.h>
5#include <random>
6
7namespace sf
8{
9
10namespace numbers
11{
12
13#if __cplusplus <= 201703L
14
15template<typename T>
16inline constexpr T pi_v = static_cast<T>(3.141592653589793238462643383279502884L);
17
18#else
19
20template<typename T>
21inline constexpr T pi_v = ::std::numbers::pi_v<T>;
22
23#endif
24}// namespace numbers
25
29template<typename T>
30T round(T value, T rnd)
31{
32 // Prevent non-integer and non-float types from implementing this template.
33 static_assert(std::is_arithmetic_v<T>, "Type T must be an arithmetic type.");
34 if constexpr (std::is_integral_v<T>)
35 {
36 return (value + rnd / T(2)) / rnd * rnd;
37 }
38 if constexpr (std::is_floating_point_v<T>)
39 {
40 // Function 'std::floor' has al float types implemented.
41 return std::floor(value / rnd + T(0.5)) * rnd;
42 }
43 return value;
44}
45
49template<typename T, typename S>
50S calculateOffset(T value, T min, T max, S len, bool clip)
51{
52 max -= min;
53 value -= min;
54 S temp = max && value ? (std::is_floating_point_v<T> ? len * (value / max) : len * value / max) : 0;
55 // Clip when required.
56 if (clip)
57 {
58 // When the len is a negative value.
59 if (len < 0)
60 {
61 return temp < len ? len : temp > S(0) ? S(0) : temp;
62 }
63 return temp > len ? len : temp < S(0) ? S(0) : temp;
64 }
65 return temp;
66}
67
76template<typename T>
77T clip(const T value, const T lower_limit, const T upper_limit)
78{
79 return value < lower_limit ? lower_limit : value > upper_limit ? upper_limit : value;
80}
81
91template<typename V, typename T>
92bool isInRange(const V value, const T from, const T to)
93{
94 // Only implementations of arithmetic values are allowed.
95 static_assert(std::is_arithmetic_v<V> || std::is_enum_v<V>, "Type V must be an arithmetic or enum type.");
96 static_assert(std::is_arithmetic_v<T> || std::is_enum_v<T>, "Type T must be an arithmetic or enum type.");
97 return value >= from && value < to;
98}
99
103template<typename T>
104T random(T start, T stop)
105{
106 static std::default_random_engine generator{};
107 std::uniform_int_distribution<T> distribution(start, stop);
108 return distribution(generator);
109}
110
118template<typename T>
119T modulo(T k, T n)
120{
121 // Only implementations of arithmetic values are allowed.
122 static_assert(std::is_arithmetic_v<T>, "Type T must be an arithmetic type.");
123 // Distinguish between floats and integers.
124 if constexpr (std::is_floating_point_v<T>)
125 {
126 // Function fmod has implementations for any floating point.
127 T r = std::fmod(k, n);
128 // if the r is less than zero, add n to put it in the [0, n-1] range if n is positive
129 // if the r is greater than zero, add n to put it in the [n-1, 0] range if n is negative
130 return (n > 0 && r < 0) || (n < 0 && r > 0) ? r + n : r;
131 }
132 else
133 {
134 T r = k % n;
135 // if the r is less than zero, add n to put it in the [0, n-1] range if n is positive
136 // if the r is greater than zero, add n to put it in the [n-1, 0] range if n is negative
137 return (n > 0 && r < 0) || (n < 0 && r > 0) ? r + n : r;
138 }
139}
140
147template<typename T>
148T toAbs(T v)
149{
150 static_assert(std::is_arithmetic_v<T>, "Type T must be an arithmetic type.");
151 if constexpr (std::is_same<T, long double>())
152 {
153 return fabsl(v);
154 }
155 if constexpr (std::is_same<T, double>())
156 {
157 return fabs(v);
158 }
159 if constexpr (std::is_same<T, float>())
160 {
161 return fabsf(v);
162 }
163 if constexpr (std::is_integral_v<T>)
164 {
165 if constexpr (std::numeric_limits<T>::is_signed)
166 {
167 if constexpr (std::is_same<T, long long int>())
168 {
169 return std::llabs(v);
170 }
171 if constexpr (std::is_same<T, long int>())
172 {
173 return std::labs(v);
174 }
175 if constexpr (std::is_same<T, int>())
176 {
177 return std::abs(v);
178 }
179 // Smaller integers are handled here.
180 return static_cast<T>(std::abs(v));
181 }
182 }
183 // Not a signed value return it as is.
184 return v;
185}
186
194template<typename T>
195T ipow(T base, int exponent)
196{
197 // Prevent non-integer types from implementing this template.
198 static_assert(std::is_integral_v<T>, "Type T must be an integer type.");
199 // Initialize the integer.
200 T rv{1};
201 for (;;)
202 {
203 // Check if the first bit is set.
204 if (exponent & 1)
205 {
206 rv *= base;
207 }
208 // Shift the bits right.
209 exponent >>= 1;
210 // When no bits are standing of the exponent done break th loop.
211 if (!exponent)
212 {
213 break;
214 }
215 // Squaring the values so far.
216 base *= base;
217 }
218 return rv;
219}
220
224template<typename T>
225constexpr T toRadians(T degrees)
226{
227 // Only implemented for floating point values.
228 static_assert(std::is_floating_point_v<T>, "Type T must be a floating point type.");
229 return degrees * (numbers::pi_v<T> / 180);
230}
231
235template<typename T>
236constexpr T toDegrees(T radians)
237{
238 // Only implemented for floating point values.
239 static_assert(std::is_floating_point_v<T>, "Type T must be a floating point type.");
240 return radians / numbers::pi_v<T> * 180;
241}
242
251template<typename T>
252bool isEqual(T a, T b, T epsilon = std::numeric_limits<T>::epsilon())
253{
254 // Only implemented for floating point values.
255 static_assert(std::is_floating_point_v<T>, "Type T must be a floating point type.");
256 return std::abs(a - b) <= epsilon;
257}
258
262template<typename T>
263bool isZero(T value, T epsilon = std::numeric_limits<T>::epsilon())
264{
265 static_assert(std::is_arithmetic_v<T>, "Type T must be an arithmetic type.");
266 if constexpr (std::is_integral_v<T>)
267 {
268 return value == std::numeric_limits<T>::denorm_min();
269 }
270 if constexpr (std::is_floating_point_v<T>)
271 {
272 return std::fabs(value) < epsilon;
273 }
274 return false;
275}
276
280template<typename T>
281bool isValidValue(T value)
282{
283 static_assert(std::is_floating_point_v<T>, "Type T must be an floating point type.");
284 return !std::isinf(value) && !std::isnan(value);
285}
286
290template<typename T, typename... Args>
291size_t maxArgumentIndex(T first, Args... args)
292{
293 T largest = first;
294 size_t idx = 0;
295 size_t idx_cur = 0;
296 // Lambda to find the largest value and its index
297 auto compare = [&largest, &idx, &idx_cur](T value) {
298 if (value > largest)
299 {
300 largest = value;
301 idx = idx_cur;
302 }
303 ++idx_cur;
304 };
305 (compare(first), ..., compare(args));// Apply to all arguments
306 return idx;
307}
308
312template<typename T, typename... Args>
313size_t minArgumentIndex(T first, Args... args)
314{
315 T largest = first;
316 size_t idx = 0;
317 size_t idx_cur = 0;
318 // Lambda to find the largest value and its index
319 auto compare = [&largest, &idx, &idx_cur](T value) {
320 if (value < largest)
321 {
322 largest = value;
323 idx = idx_cur;
324 }
325 ++idx_cur;
326 };
327 (compare(first), ..., compare(args));// Apply to all arguments
328 return idx;
329}
330
338template<typename T, size_t N>
339size_t maxArrayIndex(const std::array<T, N>& arr)
340{
341 T cur = arr[0];
342 size_t index = 0;
343 for (size_t i = 1; i < arr.size(); ++i)
344 {
345 if (arr[i] > cur)
346 {
347 cur = arr[i];
348 index = i;
349 }
350 }
351 return index;
352}
353
361template<typename T, size_t N>
362size_t minArrayIndex(const std::array<T, N>& arr)
363{
364 T cur = arr[0];
365 size_t index = 0;
366 for (size_t i = 1; i < arr.size(); ++i)
367 {
368 if (arr[i] < cur)
369 {
370 cur = arr[i];
371 index = i;
372 }
373 }
374 return index;
375}
376
385_MISC_FUNC int precision(double value);
386
394_MISC_FUNC int digits(double value);
395
402template<typename T>
403std::pair<T, int> getMantissaExponent(T value)
404{
405 // Allow only floating point values.
406 static_assert(std::is_floating_point_v<T>, "Type T must be a floating point type.");
407 // Return zero for value zero.
408 if (isZero(value))
409 return {0, 0};
410 auto exponent = std::floor(std::log10(std::abs(value)));
411 auto mantissa = value / std::pow(10, exponent);
412 // Adjust mantissa and exponent to ensure |mantissa| is between 0.1 and 1.0
413 if (std::abs(mantissa) < 0.1)
414 {
415 mantissa *= 10;
416 exponent -= 1;
417 }
418 else if (abs(mantissa) >= 1.0)
419 {
420 mantissa /= 10;
421 exponent += 1;
422 }
423 return {mantissa, exponent};
424}
425
433template<typename T>
434int magnitude(T value)
435{
436 return getMantissaExponent(value).second;
437}
438
447
458_MISC_FUNC int requiredDigits(double round_val, double min_val, double max_val);
459
460}// namespace sf
#define _MISC_FUNC
Definition misc/global.h:39
constexpr T pi_v
Definition misc/gen/math.h:16
Definition Application.h:10
bool isInRange(const V value, const T from, const T to)
Checks if the passed value is in the given range.
Definition misc/gen/math.h:92
size_t minArgumentIndex(T first, Args... args)
Finds the index of the smallest element passed as an argument.
Definition misc/gen/math.h:313
T ipow(T base, int exponent)
Fast integer power-of function.
Definition misc/gen/math.h:195
size_t minArrayIndex(const std::array< T, N > &arr)
Finds the largest element index of the passed array.
Definition misc/gen/math.h:362
int magnitude(T value)
Gets the order of magnitude of the passed floating point value. Examples: magnitude(0....
Definition misc/gen/math.h:434
T modulo(T k, T n)
Modulo template function.
Definition misc/gen/math.h:119
constexpr T toRadians(T degrees)
Converts degrees to radians.
Definition misc/gen/math.h:225
size_t maxArgumentIndex(T first, Args... args)
Finds the index of the largest element passed as an argument.
Definition misc/gen/math.h:291
bool isEqual(T a, T b, T epsilon=std::numeric_limits< T >::epsilon())
Compares 2 floating point values of the same type with a given epsilon.
Definition misc/gen/math.h:252
T clip(const T value, const T lower_limit, const T upper_limit)
Template function clipping the given value between an upper_limit and lower_limit.
Definition misc/gen/math.h:77
constexpr T toDegrees(T radians)
Converts radians to degrees.
Definition misc/gen/math.h:236
size_t maxArrayIndex(const std::array< T, N > &arr)
Finds the largest element index of the passed array.
Definition misc/gen/math.h:339
_MISC_FUNC int precision(double value)
Returns the precision of the passed floating point value. This is the amount of characters after the ...
std::pair< T, int > getMantissaExponent(T value)
Gets the mantissa and exponent part of a floating point value.
Definition misc/gen/math.h:403
_MISC_FUNC int magnitudeObsolete(double value)
Gets the order of magnitude of the passed double value. Examples: magnitude(0.001234) => -2 magnitude...
bool isZero(T value, T epsilon=std::numeric_limits< T >::epsilon())
Check if the passed value is zero or near zero according the given epsilon.
Definition misc/gen/math.h:263
T random(T start, T stop)
Generates random numbers within a specified integer range.
Definition misc/gen/math.h:104
T round(T value, T rnd)
Rounds the passed value to a multiple of the rnd value.
Definition misc/gen/math.h:30
_MISC_FUNC int digits(double value)
Returns the amount of digits which are significant for the value. When the value is 12300....
S calculateOffset(T value, T min, T max, S len, bool clip)
Calculates the offset for a given range and set point.
Definition misc/gen/math.h:50
bool isValidValue(T value)
Check if the passed value is not NaN or infinity.
Definition misc/gen/math.h:281
T toAbs(T v)
Gets the absolute value of a passed scalar value.
Definition misc/gen/math.h:148
_MISC_FUNC int requiredDigits(double round_val, double min_val, double max_val)
Gets the amount of required digits needed when drawing a scale.