HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
polynomial.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/math.hpp"
7
8namespace tt {
9
10template<typename T, int N>
11struct results {
12 static constexpr int maxCount = N;
13 using element_type = T;
14 using const_iterator = typename std::array<T,N>::const_iterator;
15
16 int count;
17 std::array<T,N> value;
18
19 results() noexcept : count(0), value() {}
20
21 gsl_suppress(bounds.4)
22 results(T a) noexcept : count(1), value() {
23 value[0] = a;
24 }
25
26 gsl_suppress(bounds.4)
27 results(T a, T b) noexcept : count(2), value() {
28 value[0] = a;
29 value[1] = b;
30 sort();
31 }
32
33 gsl_suppress(bounds.4)
34 results(T a, T b, T c) noexcept : count(3), value() {
35 value[0] = a;
36 value[1] = b;
37 value[2] = c;
38 sort();
39 }
40
41 template<int O, typename std::enable_if_t<std::less<int>{}(O,N), int> = 0>
42 gsl_suppress2(bounds.2,bounds.4)
43 results(results<T,O> const &other) noexcept : count(other.count), value() {
44 if constexpr (O > 0) {
45 for (int i = 0; i < other.maxCount; i++) {
46 value[i] = other.value[i];
47 }
48 }
49 }
50
51 int size() const noexcept {
52 return (count >= 0) ? count : 0;
53 }
54
55 bool hasInfiniteResults() const noexcept {
56 return count < 0;
57 }
58
59 const_iterator begin() const noexcept {
60 return value.begin();
61 }
62
63 const_iterator end() const noexcept {
64 return value.begin() + size();
65 }
66
67
68 void sort() noexcept {
69 std::sort(value.begin(), value.begin() + size());
70 }
71
72 void add(T a) noexcept {
73 value.at(count++) = a;
74 sort();
75 }
76};
77
78template<typename T, int N, typename U>
79gsl_suppress2(bounds.2,bounds.4)
80inline results<T, N> operator-(results<T, N> lhs, U const &rhs) noexcept
81{
82 for (int i = 0; i < lhs.maxCount; i++) {
83 lhs.value[i] -= rhs;
84 }
85 return lhs;
86}
87
88template<typename T>
89inline results<T,0> infinitResults() noexcept {
90 results<T,0> r;
91 r.count = -1;
92 return r;
93}
94
95template<typename T, int N>
96inline std::ostream& operator<<(std::ostream& os, results<T,N> const &r)
97{
98 os << "[";
99 tt_assert(r.count <= r.maxCount);
100 for (int i = 0; i < r.count; i++) {
101 if (i > 0) {
102 os << ", ";
103 }
104 os << r.value.at(i);
105 }
106 os << "]";
107 return os;
108}
109
120template<typename T>
121inline results<T,1> solvePolynomial(T const &a, T const &b) noexcept {
122 if (a != 0) {
123 return { -(b / a) };
124 } else if (b == 0) {
125 // Any value of x is correct.
126 return infinitResults<T>();
127 } else {
128 // None of the values for x is correct.
129 return {};
130 }
131}
132
144template<typename T>
145inline results<T,2> solvePolynomial(T const &a, T const &b, T const &c) noexcept {
146 if (a == 0) {
147 return solvePolynomial(b, c);
148 } else {
149 ttlet D = b*b - static_cast<T>(4)*a*c;
150 if (D < 0) {
151 return {};
152 } else if (D == 0) {
153 return { -b / (static_cast<T>(2)*a) };
154 } else {
155 ttlet Dsqrt = sqrt(D);
156 return {
157 (-b - Dsqrt) / (static_cast<T>(2)*a),
158 (-b + Dsqrt) / (static_cast<T>(2)*a)
159 };
160 }
161 }
162}
163
166template<typename T>
167inline results<T,3> solveDepressedCubicTrig(T const &p, T const &q) noexcept {
168 constexpr T oneThird = static_cast<T>(1) / static_cast<T>(3);
169 constexpr T pi2_3 = (static_cast<T>(2) / static_cast<T>(3)) * static_cast<T>(pi);
170 constexpr T pi4_3 = (static_cast<T>(4) / static_cast<T>(3)) * static_cast<T>(pi);
171
172 ttlet U = oneThird * acos(((static_cast<T>(3)*q) / (static_cast<T>(2)*p)) * sqrt(static_cast<T>(-3)/p));
173 ttlet V = static_cast<T>(2) * sqrt(-oneThird * p);
174
175 ttlet t0 = V * cos(U);
176 ttlet t1 = V * cos(U - pi2_3);
177 ttlet t2 = V * cos(U - pi4_3);
178 return { t0, t1, t2 };
179}
180
181template<typename T>
182inline results<T,3> solveDepressedCubicCardano(T const &p, T const &q, T const &D) noexcept {
183 ttlet sqrtD = sqrt(D);
184 ttlet minusHalfQ = static_cast<T>(-0.5) * q;
185 ttlet v = cbrt(minusHalfQ + sqrtD);
186 ttlet w = cbrt(minusHalfQ - sqrtD);
187 return { v + w };
188}
189
204template<typename T>
205inline results<T,3> solveDepressedCubic(T const &p, T const &q) noexcept {
206 constexpr T oneForth = static_cast<T>(1) / static_cast<T>(4);
207 constexpr T oneTwentySeventh = static_cast<T>(1) / static_cast<T>(27);
208
209 if (p == 0.0 && q == 0.0) {
210 return { static_cast<T>(0) };
211
212 } else {
213 ttlet D = oneForth*q*q + oneTwentySeventh*p*p*p;
214
215 if (D < 0 && p != 0.0) {
216 // Has three real roots.
217 return solveDepressedCubicTrig(p, q);
218
219 } else if (D == 0 && p != 0.0) {
220 // Has two real roots, or maybe one root
221 ttlet t0 = (static_cast<T>(3)*q) / p;
222 ttlet t1 = (static_cast<T>(-3)*q) / (static_cast<T>(2)*p);
223 return {t0, t1, t1};
224
225 } else {
226 // Has one real root.
227 return solveDepressedCubicCardano(p, q, D);
228 }
229 }
230}
231
240template<typename T>
241inline results<T,3> solvePolynomial(T const &a, T const &b, T const &c, T const &d) noexcept {
242 if (a == 0) {
243 return solvePolynomial(b, c, d);
244
245 } else {
246 ttlet p = (static_cast<T>(3)*a*c - b*b) / (static_cast<T>(3)*a*a);
247 ttlet q = (static_cast<T>(2)*b*b*b - static_cast<T>(9)*a*b*c + static_cast<T>(27)*a*a*d) / (static_cast<T>(27)*a*a*a);
248
249 ttlet r = solveDepressedCubic(p, q);
250
251 ttlet b_3a = b / (static_cast<T>(3)*a);
252
253 return r - b_3a;
254 }
255}
256
257}
Definition polynomial.hpp:11
T acos(T... args)
T at(T... args)
T begin(T... args)
T cbrt(T... args)
T cos(T... args)
T sort(T... args)
T sqrt(T... args)