Ocean
Loading...
Searching...
No Matches
Equation.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef META_OCEAN_MATH_EQUATION_H
9#define META_OCEAN_MATH_EQUATION_H
10
11#include "ocean/math/Math.h"
12#include "ocean/math/Numeric.h"
13
15
16#include <complex>
17
18namespace Ocean
19{
20
21// Forward declaration.
22template <typename T> class EquationT;
23
24/**
25 * Definition of the Equation object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single or double precision float data type.
26 * @see EquationT
27 * @ingroup math
28 */
30
31/**
32 * Definition of the Equation class using double values
33 * @see EquationT
34 * @ingroup math
35 */
37
38/**
39 * Definition of the Equation class using float values
40 * @see EquationT
41 * @ingroup math
42 */
44
45/**
46 * This class provides several functions to solve equations with different degree using floating point values with the precission specified by type T.
47 * @tparam T Type of passed floating point values
48 * @see Equation, EquationF, EquationD.
49 * @ingroup math
50 */
51template <typename T>
53{
54 public:
55
56 /**
57 * Solves a linear eqation with the form:
58 * <pre>
59 * ax + b = 0
60 * </pre>
61 * @param a A parameter, with range (-infinity, infinity) \ {0}, (must not be 0)
62 * @param b B parameter, with range (-infinity, infinity)
63 * @param x Resulting solution
64 * @return True, if succeeded
65 */
66 static bool solveLinear(const T a, const T b, T& x);
67
68 /**
69 * Solves an quadratic equation with the form:
70 * <pre>
71 * ax^2 + bx + c = 0
72 * </pre>
73 * @param a A parameter, with range (-infinity, infinity) \ {0}, (must not be 0)
74 * @param b B parameter, with range (-infinity, infinity)
75 * @param c C parameter, with range (-infinity, infinity)
76 * @param x1 First resulting solution, with range (-infinity, infinity)
77 * @param x2 Second resulting solution, with range (-infinity, infinity)
78 * @return True, if succeeded
79 */
80 static bool solveQuadratic(const T a, const T b, const T c, T& x1, T& x2);
81
82 /**
83 * Solves a cubic equation with the from:
84 * <pre>
85 * ax^3 + bx^2 + cx + d = 0
86 * </pre>
87 * @param a A parameter, with range (-infinity, infinity) \ {0}, (must not be 0)
88 * @param b B parameter, with range (-infinity, infinity)
89 * @param c C parameter, with range (-infinity, infinity)
90 * @param d D parameter, with range (-infinity, infinity)
91 * @param x1 First resulting solution, with range (-infinity, infinity)
92 * @param x2 Second resulting solution, with range (-infinity, infinity)
93 * @param x3 Third resulting solution, with range (-infinity, infinity)
94 * @param refine True, to refine the calculated solutions with an iterative algorithm; False, to use the roots as calculated
95 * @return The number of solutions, with range [0, 3]
96 */
97 static unsigned int solveCubic(const T a, const T b, const T c, const T d, T& x1, T& x2, T& x3, const bool refine = true);
98
99 /**
100 * Solves a quartic equation with the form:
101 * <pre>
102 * ax^4 + bx^3 + cx^2 + dx + e = 0
103 * </pre>
104 * @param a A parameter, with range (-infinity, infinity) \ {0}, (must not be 0)
105 * @param b B parameter, with range (-infinity, infinity)
106 * @param c C parameter, with range (-infinity, infinity)
107 * @param d D parameter, with range (-infinity, infinity)
108 * @param e E parameter, with range (-infinity, infinity)
109 * @param x Array with at least four scalar values receiving the (at most) four solutions
110 * @param refine True, to refine the calculated solutions with an iterative algorithm; False, to use the roots as calculated
111 * @return The number of solutions, with range [0, 4]
112 */
113 static unsigned int solveQuartic(const T a, const T b, const T c, const T d, const T e, T* x, const bool refine = true);
114
115 /**
116 * Optimizes a root of a cubic equation using Newton-Raphson iterations.
117 * The function optimizes a known x for the following equation:
118 * <pre>
119 * ax^3 + bx^2 + cx + d = 0
120 * </pre>
121 * @param a A parameter, with range (-infinity, infinity) \ {0}, (must not be 0)
122 * @param b B parameter, with range (-infinity, infinity)
123 * @param c C parameter, with range (-infinity, infinity)
124 * @param d D parameter, with range (-infinity, infinity)
125 * @param x The known root to optimize, with range (-infinity, infinity)
126 * @param maxIterations The maximum number of Newton-Raphson iterations, with range [1, infinity)
127 * @param updateFactor The update factor for the Newton-Raphson iterations, with range (0, 2]
128 * @return The number of applied iterations, with range [0, maxIterations], 0 if the root could not be optimized
129 */
130 static unsigned int optimizeCubic(const T a, const T b, const T c, const T d, T& x, const unsigned int maxIterations = 10u, const T updateFactor = T(1.0));
131
132 /**
133 * Optimizes a root of a quartic equation using Newton-Raphson iterations.
134 * The function optimizes a known x for the following equation:
135 * <pre>
136 * ax^4 + bx^3 + cx^2 + dx + e = 0
137 * </pre>
138 * @param a A parameter, with range (-infinity, infinity) \ {0}, (must not be 0)
139 * @param b B parameter, with range (-infinity, infinity)
140 * @param c C parameter, with range (-infinity, infinity)
141 * @param d D parameter, with range (-infinity, infinity)
142 * @param e E parameter, with range (-infinity, infinity)
143 * @param x The known root to optimize, with range (-infinity, infinity)
144 * @param maxIterations The maximum number of Newton-Raphson iterations, with range [1, infinity)
145 * @param updateFactor The update factor for the Newton-Raphson iterations, with range (0, 2]
146 * @return The number of applied iterations, with range [0, maxIterations], 0 if the root could not be optimized
147 */
148 static unsigned int optimizeQuartic(const T a, const T b, const T c, const T d, const T e, T& x, const unsigned int maxIterations = 10u, const T updateFactor = T(1.0));
149};
150
151template <typename T>
152bool EquationT<T>::solveLinear(const T a, const T b, T& x)
153{
154 ocean_assert(NumericT<T>::isNotEqualEps(a));
155
156 // ax + b = 0
157
159 {
160 return false;
161 }
162
163 x = -b / a;
164 return true;
165}
166
167template <typename T>
168bool EquationT<T>::solveQuadratic(const T a, const T b, const T c, T& x1, T& x2)
169{
170 ocean_assert(NumericT<T>::isNotEqualEps(a));
171
172 // ax^2 + bx + c = 0
173
174 // see Numerical Recipes in C++
175 // x = (-b ± sqrt(b^2 - 4ac)) / 2a
176
178 {
179 return false;
180 }
181
182 const T value = b * b - T(4) * a * c;
183
184 if (value < T(0))
185 {
186 return false;
187 }
188
189 if (NumericT<T>::isEqualEps(value))
190 {
191 // x = (-b ± sqrt(0)) / 2a
192
193 x1 = -b / (T(2) * a);
194 x2 = x1;
195
196 return true;
197 }
198
199 const T q = T(-0.5) * (b + NumericT<T>::copySign(NumericT<T>::sqrt(value), b));
200
202 {
203 x1 = 0;
204 x2 = 0;
205 return true;
206 }
207
208 x1 = q / a;
209 x2 = c / q;
210
211#ifdef OCEAN_DEBUG
212 if (std::is_same<T, float>::value)
213 {
214 // for 32 bit float values we have to weaken the zero accuracy
215 ocean_assert(NumericT<T>::isEqual(a * x1 * x1 + b * x1 + c, T(0), NumericT<T>::weakEps() * NumericT<T>::abs(x1)));
216 ocean_assert(NumericT<T>::isEqual(a * x2 * x2 + b * x2 + c, T(0), NumericT<T>::weakEps() * NumericT<T>::abs(x2)));
217 }
218 else
219 {
220 ocean_assert(NumericT<T>::isWeakEqualEps(a * x1 * x1 + b * x1 + c));
221 ocean_assert(NumericT<T>::isWeakEqualEps(a * x2 * x2 + b * x2 + c));
222 }
223#endif
224
225 return true;
226}
227
228template <typename T>
229unsigned int EquationT<T>::solveCubic(const T a, const T b, const T c, const T d, T& x1, T& x2, T& x3, const bool refine)
230{
231 ocean_assert(NumericT<T>::isNotEqualEps(a));
232
233 // ax^3 + bx^2 + cx + d = 0
234 // see Numerical Recipes in C++
235
237 {
238 return 0u;
239 }
240
241 const T a1 = 1 / a;
242 const T alpha = b * a1;
243 const T beta = c * a1;
244 const T gamma = d * a1;
245
246 // x^3 + alpha x^2 + beta x + gamma = 0
247
248 // alpha2 = alpha^2
249 const T alpha2 = alpha * alpha;
250
251 // q = (alpha^2 - 3*beta) / 9
252 const T q = (alpha2 - T(3) * beta) * T(0.11111111111111111111111111111111);
253
254 // r = (2*alpha^3 - 9*alpha*beta + 27*gamma) / 54
255 const T r = (T(2) * alpha2 * alpha - T(9) * alpha * beta + T(27) * gamma) * T(0.018518518518518518518518518518519);
256
257 // r2 = r^2
258 const T r2 = r * r;
259
260 // q3 = q^3
261 const T q3 = q * q * q;
262
263 if (r2 <= q3 + NumericT<T>::eps() && q > NumericT<T>::eps())
264 {
265 const T sqrtQ = NumericT<T>::sqrt(q);
266
267 // angle = arccos(r / sqrt(q^3))
268 // angle_3 = angle / 3
269 const T angle_3 = NumericT<T>::acos(minmax<T>(-1, r / (q * sqrtQ), 1)) * T(0.33333333333333333333333333333333);
270
271 // alpha_3 = alpha / 3
272 const T alpha_3 = alpha * T(0.33333333333333333333333333333333);
273
274 const T factor = T(-2) * sqrtQ;
275
276 // x1 = -2 sqrt(q) * cos(angle / 3) - alpha / 3
277 x1 = factor * NumericT<T>::cos(angle_3) - alpha_3;
278
279 // x2 = -2 sqrt(q) * cos((angle + 2pi) / 3) - alpha / 3
280 x2 = factor * NumericT<T>::cos(angle_3 + T(2.0943951023931954923084289221863)) - alpha_3;
281
282 // x3 = -2 sqrt(q) * cos((angle - 2pi) / 3) - alpha / 3
283 x3 = factor * NumericT<T>::cos(angle_3 - T(2.0943951023931954923084289221863)) - alpha_3;
284
285 if (refine)
286 {
287 optimizeCubic(a, b, c, d, x1);
288 optimizeCubic(a, b, c, d, x2);
289 optimizeCubic(a, b, c, d, x3);
290 }
291
292 return 3u;
293 }
294
295 ocean_assert(r2 - q3 >= -NumericT<T>::eps());
296
297 // m = -sign(r) * [abs(r) + sqrt(r^2 - q^3)]^(1/3)
298 const T m = -NumericT<T>::copySign(pow(NumericT<T>::abs(r) + NumericT<T>::sqrt(std::max(T(0), r2 - q3)), T(0.33333333333333333333333333333333)), r);
299
300 // n = 0, if m == 0
301 // n = q / m, if m != 0
302 const T n = NumericT<T>::isEqualEps(m) ? 0 : q / m;
303
304 // x1 = (m + n) - alpha / 3
305 x1 = m + n - alpha * T(0.33333333333333333333333333333333);
306
307 if (refine)
308 {
309 optimizeCubic(a, b, c, d, x1);
310 }
311
312 return 1u;
313}
314
315template <typename T>
316unsigned int EquationT<T>::solveQuartic(const T a, const T b, const T c, const T d, const T e, T* x, const bool refine)
317{
318 ocean_assert(NumericT<T>::isNotEqualEps(a));
319 ocean_assert(x != nullptr);
320
321 // ax^4 + bx^3 + cx^2 + dx + e = 0
322
324 {
325 return 0u;
326 }
327
328 // simplification using substitution:
329 /// y^4 + alpha * y^2 + beta * y + gamma = 0
330
331 // 1 / a
332 const T a1 = T(1.0) / a;
333
334 // b / a
335 const T b_a = b * a1;
336
337 // c / a
338 const T c_a = c * a1;
339
340 // (b * b) / (a * a)
341 const T b_a2 = b_a * b_a;
342
343 // (b * b * b) / (a * a * a)
344 const T b_a3 = b_a2 * b_a;
345
346 // d / a
347 const T d_a = d * a1;
348
349 //const T alpha = T(-0.375) * (b / a) * (b / a) + c / a;
350 const T alpha = T(-0.375) * b_a2 + c_a;
351
352 //const T beta = T(0.125) * (b / a) * (b / a) * (b / a) - T(0.5) * (b / a) * (c / a) + (d / a);
353 const T beta = T(0.125) * b_a3 - T(0.5) * b_a * c_a + d_a;
354
355 //const T gamma = T(-0.01171875) * (b / a) * (b / a) * (b / a) * (b / a) + T(0.0625) * (b / a) * (b / a) * (c / a) - T(0.25) * (b / a) * (d / a) + e / a;
356 const T gamma = T(-0.01171875) * b_a3 * b_a + T(0.0625) * b_a2 * c_a - T(0.25) * b_a * d_a + e * a1;
357
358 // y^4 + alpha y^2 + beta y + gamma = 0
359
360 unsigned int solutions = 0u;
361
362 if (NumericT<T>::isEqualEps(beta))
363 {
364 const std::complex<T> cx1 = std::complex<T>(T(-0.25)) * std::complex<T>(b / a) + NumericT<T>::sqrt(std::complex<T>(T(0.5)) * (std::complex<T>(-alpha) + NumericT<T>::sqrt(std::complex<T>(alpha * alpha - 4 * gamma))));
365 const std::complex<T> cx2 = std::complex<T>(T(-0.25)) * std::complex<T>(b / a) + NumericT<T>::sqrt(std::complex<T>(T(0.5)) * (std::complex<T>(-alpha) - NumericT<T>::sqrt(std::complex<T>(alpha * alpha - 4 * gamma))));
366 const std::complex<T> cx3 = std::complex<T>(T(-0.25)) * std::complex<T>(b / a) - NumericT<T>::sqrt(std::complex<T>(T(0.5)) * (std::complex<T>(-alpha) + NumericT<T>::sqrt(std::complex<T>(alpha * alpha - 4 * gamma))));
367 const std::complex<T> cx4 = std::complex<T>(T(-0.25)) * std::complex<T>(b / a) - NumericT<T>::sqrt(std::complex<T>(T(0.5)) * (std::complex<T>(-alpha) - NumericT<T>::sqrt(std::complex<T>(alpha * alpha - 4 * gamma))));
368
369 if (NumericT<T>::isEqualEps(cx1.imag()))
370 {
371 x[solutions++] = cx1.real();
372 }
373
374 if (NumericT<T>::isEqualEps(cx2.imag()))
375 {
376 x[solutions++] = cx2.real();
377 }
378
379 if (NumericT<T>::isEqualEps(cx3.imag()))
380 {
381 x[solutions++] = cx3.real();
382 }
383
384 if (NumericT<T>::isEqualEps(cx4.imag()))
385 {
386 x[solutions++] = cx4.real();
387 }
388 }
389 else
390 {
391 //const std::complex<T> p(-(alpha * alpha) / T(12.0) - gamma);
392 const std::complex<T> p(T(-0.08333333333333333333333333333333) * alpha * alpha - gamma);
393
394 //const std::complex<T> q(-(alpha * alpha * alpha) / T(108.0) + (alpha * gamma) / T(3.0) - (beta * beta) / T(8.0));
395 const std::complex<T> q(T(-0.00925925925925925925925925925926) * alpha * alpha * alpha + T(0.33333333333333333333333333333333) * alpha * gamma - T(0.125) * beta * beta);
396
397 const std::complex<T> qqSqr = NumericT<T>::sqrt(std::complex<T>(T(0.25)) * q * q + std::complex<T>(T(0.03703703703703703703703703703704)) * p * p * p);
398
399 const std::complex<T> r(std::complex<T>(T(-0.5)) * q + qqSqr);
401 {
402 return 0u;
403 }
404
405 const std::complex<T> u = NumericT<T>::pow(std::complex<T>(r), T(0.33333333333333333333333333333333));
406
408 {
409 return 0u;
410 }
411
412 std::complex<T> y;
413 if (NumericT<T>::isEqualEps(u.real()) && NumericT<T>::isEqualEps(u.imag()))
414 {
415 y = std::complex<T>(T(-0.83333333333333333333333333333333) * alpha) + u - NumericT<T>::pow(std::complex<T>(q), T(0.33333333333333333333333333333333));
416 }
417 else
418 {
419 y = std::complex<T>(T(-0.83333333333333333333333333333333) * alpha) + u - p / (std::complex<T>(3) * u);
420 }
421
422 const std::complex<T> w(NumericT<T>::sqrt(std::complex<T>(alpha) + std::complex<T>(T(2)) * y));
423
424 //const std::complex<T> cx1 = std::complex<T>(T(-0.25)) * std::complex<T>(b / a) + std::complex<T>(T(0.5)) * (w + NumericT<T>::sqrt(std::complex<T>(-1) * (std::complex<T>(3) * std::complex<T>(alpha) + std::complex<T>(2) * y + std::complex<T>(2) * std::complex<T>(beta) / w)));
425
427 {
428 return 0u;
429 }
430
431 const std::complex<T> beta2_w(std::complex<T>(T(2) * beta) / w);
432 const std::complex<T> alpha3y2 = std::complex<T>(T(3) * alpha) + std::complex<T>(T(2)) * y;
433 const std::complex<T> b_a4(T(-0.25) * b_a);
434
435 const std::complex<T> sqrtPositive(NumericT<T>::sqrt(-alpha3y2 - beta2_w));
436 const std::complex<T> sqrtNegative(NumericT<T>::sqrt(-alpha3y2 + beta2_w));
437
438 const std::complex<T> cx1 = b_a4 + std::complex<T>(T(0.5)) * (w + sqrtPositive);
439 const std::complex<T> cx2 = b_a4 + std::complex<T>(T(0.5)) * (w - sqrtPositive);
440 const std::complex<T> cx3 = b_a4 + std::complex<T>(T(0.5)) * (-w + sqrtNegative);
441 const std::complex<T> cx4 = b_a4 + std::complex<T>(T(0.5)) * (-w - sqrtNegative);
442
443 if (NumericT<T>::isEqualEps(cx1.imag()))
444 {
445 x[solutions++] = cx1.real();
446 }
447
448 if (NumericT<T>::isEqualEps(cx2.imag()))
449 {
450 x[solutions++] = cx2.real();
451 }
452
453 if (NumericT<T>::isEqualEps(cx3.imag()))
454 {
455 x[solutions++] = cx3.real();
456 }
457
458 if (NumericT<T>::isEqualEps(cx4.imag()))
459 {
460 x[solutions++] = cx4.real();
461 }
462 }
463
464 // first, we try to refine/optimize the solutions
465
466 if (refine)
467 {
468 for (unsigned int n = 0u; n < solutions; ++n)
469 {
470 optimizeQuartic(a, b, c, d, e, x[n]);
471 }
472 }
473
474 // finally, we remove all solutions which are not accurate enough
475
476 unsigned int nOutput = 0u;
477 for (unsigned int nInput = 0u; nInput < solutions; ++nInput)
478 {
479 const T value = x[nInput];
480
481 if (NumericT<T>::isWeakEqualEps(value * value * value * value * a + value * value * value * b + value * value * c + value * d + e))
482 {
483 // the solution is accurate enough
484
485 if (nOutput != nInput)
486 {
487 x[nOutput] = x[nInput];
488 }
489
490 ++nOutput;
491 }
492 }
493
494 solutions = nOutput;
495
496 return solutions;
497}
498
499template <typename T>
500unsigned int EquationT<T>::optimizeCubic(const T a, const T b, const T c, const T d, T& root, const unsigned int maxIterations, const T updateFactor)
501{
502 ocean_assert(maxIterations >= 1u);
503 ocean_assert(updateFactor > T(0) && updateFactor <= T(2));
504
505 // Newton-Raphson iteration: xNew = xOld - f(xOld) / f'(xOld)
506
507 // where f(x) = ax^3 + bx^2 + cx + d
508 // and f'(x) = 3ax^2 + 2bx + c
509
510 for (unsigned int nIteration = 0u; nIteration < maxIterations; ++nIteration)
511 {
512 const T x = root;
513
514 const T fx = a * x * x * x + b * x * x + c * x + d;
515
517 {
518 return nIteration;
519 }
520
521 const T fdx = T(3) * a * x * x + T(2) * b * x + c;
522
524 {
525 return nIteration;
526 }
527
528 const T delta = fx / fdx;
529 const T newX = x - delta * updateFactor;
530
531 const T newFx = a * newX * newX * newX + b * newX * newX + c * newX + d;
532
533 if (NumericT<T>::abs(fx) < NumericT<T>::abs(newFx))
534 {
535 // the optimization failed
536 return nIteration;
537 }
538
539 root = newX;
540
541 // we have converged
542 if (NumericT<T>::isEqualEps(delta))
543 {
544 return nIteration + 1u;
545 }
546 }
547
548 return maxIterations;
549}
550
551template <typename T>
552unsigned int EquationT<T>::optimizeQuartic(const T a, const T b, const T c, const T d, const T e, T& root, const unsigned int maxIterations, const T updateFactor)
553{
554 ocean_assert(maxIterations >= 1u);
555 ocean_assert(updateFactor > T(0) && updateFactor <= T(2));
556
557 // Newton-Raphson iteration: xNew = xOld - f(xOld) / f'(xOld)
558
559 // where f(x) = ax^4 + bx^3 + cx^2 + dx + e
560 // and f'(x) = 4ax^3 + 3bx^2 + 2cx + d
561
562 for (unsigned int nIteration = 0u; nIteration < maxIterations; ++nIteration)
563 {
564 const T x = root;
565 const T x2 = x * x;
566 const T x3 = x2 * x;
567 const T x4 = x3 * x;
568
569 const T fx = a * x4 + b * x3 + c * x2 + d * x + e;
570
572 {
573 return nIteration;
574 }
575
576 const T fdx = T(4) * a * x3 + T(3) * b * x2 + T(2) * c * x + d;
577
579 {
580 return nIteration;
581 }
582
583 const T delta = fx / fdx;
584 const T newX = x - delta * updateFactor;
585
586 const T newFx = a * newX * newX * newX * newX + b * newX * newX * newX + c * newX * newX + d * newX + e;
587
588 if (NumericT<T>::abs(fx) < NumericT<T>::abs(newFx))
589 {
590 // the optimization failed
591 return nIteration;
592 }
593
594 root = newX;
595
596 // we have converged
597 if (NumericT<T>::isEqualEps(delta))
598 {
599 return nIteration + 1u;
600 }
601 }
602
603 return maxIterations;
604}
605
606}
607
608#endif // META_OCEAN_MATH_EQUATION_H
This class provides several functions to solve equations with different degree using floating point v...
Definition Equation.h:53
static unsigned int solveQuartic(const T a, const T b, const T c, const T d, const T e, T *x, const bool refine=true)
Solves a quartic equation with the form:
Definition Equation.h:316
static unsigned int optimizeCubic(const T a, const T b, const T c, const T d, T &x, const unsigned int maxIterations=10u, const T updateFactor=T(1.0))
Optimizes a root of a cubic equation using Newton-Raphson iterations.
Definition Equation.h:500
static unsigned int optimizeQuartic(const T a, const T b, const T c, const T d, const T e, T &x, const unsigned int maxIterations=10u, const T updateFactor=T(1.0))
Optimizes a root of a quartic equation using Newton-Raphson iterations.
Definition Equation.h:552
static bool solveQuadratic(const T a, const T b, const T c, T &x1, T &x2)
Solves an quadratic equation with the form:
Definition Equation.h:168
static bool solveLinear(const T a, const T b, T &x)
Solves a linear eqation with the form:
Definition Equation.h:152
static unsigned int solveCubic(const T a, const T b, const T c, const T d, T &x1, T &x2, T &x3, const bool refine=true)
Solves a cubic equation with the from:
Definition Equation.h:229
This class provides basic numeric functionalities.
Definition Numeric.h:57
static T pow(const T x, const T y)
Returns x raised to the power of y.
Definition Numeric.h:1866
static T sqrt(const T value)
Returns the square root of a given value.
Definition Numeric.h:1537
static constexpr T eps()
Returns a small epsilon.
static constexpr bool isEqualEps(const T value)
Returns whether a value is smaller than or equal to a small epsilon.
Definition Numeric.h:2096
static constexpr T copySign(const T signReceiver, const T signProvider)
Copies the sign of a given value to another one.
Definition Numeric.h:3273
static T cos(const T value)
Returns the cosine of a given value.
Definition Numeric.h:1588
static T acos(const T value)
Returns the arccosine of a given value.
Definition Numeric.h:2916
The namespace covering the entire Ocean framework.
Definition Accessor.h:15