HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
polynomial.hpp
1// Copyright Take Vos 2019-2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "math.hpp"
8#include <numbers>
9#include <array>
10
11namespace tt {
12
13template<typename T, int N>
14struct results {
15 static constexpr int maxCount = N;
16 using element_type = T;
18 using const_iterator = typename array_type::const_iterator;
19
20 int count;
21 array_type value;
22
23 results() noexcept : count(0), value() {}
24
25 results(T a) noexcept : count(1), value() {
26 value[0] = a;
27 }
28
29 results(T a, T b) noexcept : count(2), value() {
30 value[0] = a;
31 value[1] = b;
32 sort();
33 }
34
35 results(T a, T b, T c) noexcept : count(3), value() {
36 value[0] = a;
37 value[1] = b;
38 value[2] = c;
39 sort();
40 }
41
42 template<int O, typename std::enable_if_t<O < N, int> = 0>
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 void sort() noexcept {
68 std::sort(value.begin(), value.begin() + size());
69 }
70
71 void add(T a) noexcept {
72 value.at(count++) = a;
73 sort();
74 }
75};
76
77template<typename T, int N, typename U>
78inline results<T, N> operator-(results<T, N> lhs, U const &rhs) noexcept
79{
80 for (int i = 0; i < lhs.maxCount; i++) {
81 lhs.value[i] -= rhs;
82 }
83 return lhs;
84}
85
86template<typename T>
87inline results<T,0> infinitResults() noexcept {
88 results<T,0> r;
89 r.count = -1;
90 return r;
91}
92
93template<typename T, int N>
94inline std::ostream& operator<<(std::ostream& os, results<T,N> const &r)
95{
96 os << "[";
97 tt_assert(r.count <= r.maxCount);
98 for (int i = 0; i < r.count; i++) {
99 if (i > 0) {
100 os << ", ";
101 }
102 os << r.value.at(i);
103 }
104 os << "]";
105 return os;
106}
107
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
146template<typename T>
147inline results<T,2> solvePolynomial(T const &a, T const &b, T const &c) noexcept {
148 if (a == 0) {
149 return solvePolynomial(b, c);
150 } else {
151 ttlet D = b*b - static_cast<T>(4)*a*c;
152 if (D < 0) {
153 return {};
154 } else if (D == 0) {
155 return { -b / (static_cast<T>(2)*a) };
156 } else {
157 ttlet Dsqrt = sqrt(D);
158 return {
159 (-b - Dsqrt) / (static_cast<T>(2)*a),
160 (-b + Dsqrt) / (static_cast<T>(2)*a)
161 };
162 }
163 }
164}
165
168template<typename T>
169inline results<T,3> solveDepressedCubicTrig(T const &p, T const &q) noexcept {
170 constexpr T oneThird = static_cast<T>(1) / static_cast<T>(3);
171 constexpr T pi2_3 = (static_cast<T>(2) / static_cast<T>(3)) * std::numbers::pi_v<T>;
172 constexpr T pi4_3 = (static_cast<T>(4) / static_cast<T>(3)) * std::numbers::pi_v<T>;
173
174 ttlet U = oneThird * acos(((static_cast<T>(3)*q) / (static_cast<T>(2)*p)) * sqrt(static_cast<T>(-3)/p));
175 ttlet V = static_cast<T>(2) * sqrt(-oneThird * p);
176
177 ttlet t0 = V * cos(U);
178 ttlet t1 = V * cos(U - pi2_3);
179 ttlet t2 = V * cos(U - pi4_3);
180 return { t0, t1, t2 };
181}
182
183template<typename T>
184inline results<T,3> solveDepressedCubicCardano(T const &p, T const &q, T const &D) noexcept {
185 ttlet sqrtD = sqrt(D);
186 ttlet minusHalfQ = static_cast<T>(-0.5) * q;
187 ttlet v = cbrt(minusHalfQ + sqrtD);
188 ttlet w = cbrt(minusHalfQ - sqrtD);
189 return { v + w };
190}
191
208template<typename T>
209inline results<T,3> solveDepressedCubic(T const &p, T const &q) noexcept {
210 constexpr T oneForth = static_cast<T>(1) / static_cast<T>(4);
211 constexpr T oneTwentySeventh = static_cast<T>(1) / static_cast<T>(27);
212
213 if (p == 0.0 && q == 0.0) {
214 return { static_cast<T>(0) };
215
216 } else {
217 ttlet D = oneForth*q*q + oneTwentySeventh*p*p*p;
218
219 if (D < 0 && p != 0.0) {
220 // Has three real roots.
221 return solveDepressedCubicTrig(p, q);
222
223 } else if (D == 0 && p != 0.0) {
224 // Has two real roots, or maybe one root
225 ttlet t0 = (static_cast<T>(3)*q) / p;
226 ttlet t1 = (static_cast<T>(-3)*q) / (static_cast<T>(2)*p);
227 return {t0, t1, t1};
228
229 } else {
230 // Has one real root.
231 return solveDepressedCubicCardano(p, q, D);
232 }
233 }
234}
235
244template<typename T>
245inline results<T,3> solvePolynomial(T const &a, T const &b, T const &c, T const &d) noexcept {
246 if (a == 0) {
247 return solvePolynomial(b, c, d);
248
249 } else {
250 ttlet p = (static_cast<T>(3)*a*c - b*b) / (static_cast<T>(3)*a*a);
251 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);
252
253 ttlet r = solveDepressedCubic(p, q);
254
255 ttlet b_3a = b / (static_cast<T>(3)*a);
256
257 return r - b_3a;
258 }
259}
260
261}
Definition polynomial.hpp:14
T acos(T... args)
T begin(T... args)
T cbrt(T... args)
T cos(T... args)
T end(T... args)
T sort(T... args)
T sqrt(T... args)