HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
polynomial.hpp
1// Copyright Take Vos 2022.
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 "utility/module.hpp"
8#include <numbers>
9#include <array>
10
11namespace hi::inline v1 {
12
13template<typename T, std::size_t N>
14class results {
15public:
16 using value_type = T;
18 using const_iterator = typename array_type::const_iterator;
19
20 constexpr results() noexcept : _size(0), _v() {}
21 constexpr results(results const&) noexcept = default;
22 constexpr results(results&&) noexcept = default;
23 constexpr results& operator=(results const&) noexcept = default;
24 constexpr results& operator=(results&&) noexcept = default;
25
26 constexpr results(value_type a) noexcept : _size(1), _v()
27 {
28 _v[0] = a;
29 }
30
31 constexpr results(value_type a, value_type b) noexcept : _size(2), _v()
32 {
33 _v[0] = a;
34 _v[1] = b;
35 }
36
37 constexpr results(value_type a, value_type b, value_type c) noexcept : _size(3), _v()
38 {
39 _v[0] = a;
40 _v[1] = b;
41 _v[2] = c;
42 }
43
44 template<std::size_t O>
45 constexpr results(results<T, O> const& other) noexcept requires(O < N) : _size(other._size), _v()
46 {
47 if constexpr (O > 0) {
48 for (auto i = 0_uz; i < other._size; i++) {
49 _v[i] = other._v[i];
50 }
51 }
52 }
53
54 [[nodiscard]] constexpr std::size_t capacity() const noexcept
55 {
56 return _capacity;
57 }
58
59 [[nodiscard]] constexpr std::size_t size() const noexcept
60 {
61 return _size;
62 }
63
64 [[nodiscard]] constexpr const_iterator begin() const noexcept
65 {
66 return _v.begin();
67 }
68
69 [[nodiscard]] constexpr const_iterator end() const noexcept
70 {
71 return _v.begin() + size();
72 }
73
74 [[nodiscard]] constexpr value_type const& operator[](std::size_t index) const noexcept
75 {
76 hi_axiom(index < _size);
77 return _v[index];
78 }
79
80 [[nodiscard]] constexpr value_type& operator[](std::size_t index) noexcept
81 {
82 hi_axiom(index < _size);
83 return _v[index];
84 }
85
86 constexpr void add(T a) noexcept
87 {
88 hi_axiom(_size < _capacity);
89 _v[_size++] = a;
90 }
91
92 [[nodiscard]] constexpr friend results operator-(results lhs, value_type rhs) noexcept
93 {
94 // For performance reasons work on the whole array. The constructors have
95 // initialized the empty elements to 0.0f.
96 for (auto i = 0_uz; i < lhs._capacity; i++) {
97 lhs._v[i] -= rhs;
98 }
99 return lhs;
100 }
101
102private:
103 static constexpr std::size_t _capacity = N;
104
105 array_type _v;
106 std::size_t _size;
107
108 template<typename O, std::size_t M>
109 friend class results;
110};
111
112
113template<typename T, std::size_t N>
114inline std::ostream& operator<<(std::ostream& os, results<T, N> const& r)
115{
116 os << "[";
117 hi_assert(r.size() <= r.capacity());
118 for (auto i = 0_uz; i < r.size(); i++) {
119 if (i > 0) {
120 os << ", ";
121 }
122 os << r[i];
123 }
124 os << "]";
125 return os;
126}
127
140template<typename T>
141hi_force_inline constexpr results<T, 1> solvePolynomial(T const& a, T const& b) noexcept
142{
143 if (a != 0) {
144 return {-(b / a)};
145 } else if (b == 0) {
146 // Any value of x is correct.
147 return {0.0f};
148 } else {
149 // None of the values for x is correct.
150 return {};
151 }
152}
153
167template<typename T>
168hi_force_inline constexpr results<T, 2> solvePolynomial(T const& a, T const& b, T const& c) noexcept
169{
170 if (a == 0) {
171 return solvePolynomial(b, c);
172 } else {
173 hilet D = b * b - static_cast<T>(4) * a * c;
174 if (D < 0) {
175 return {};
176 } else if (D == 0) {
177 return {-b / (static_cast<T>(2) * a)};
178 } else {
179 hilet Dsqrt = sqrt(D);
180 return {(-b - Dsqrt) / (static_cast<T>(2) * a), (-b + Dsqrt) / (static_cast<T>(2) * a)};
181 }
182 }
183}
184
187template<typename T>
188hi_force_inline results<T, 3> solveDepressedCubicTrig(T const& p, T const& q) noexcept
189{
190 constexpr T oneThird = static_cast<T>(1) / static_cast<T>(3);
191 constexpr T pi2_3 = (static_cast<T>(2) / static_cast<T>(3)) * std::numbers::pi_v<T>;
192 constexpr T pi4_3 = (static_cast<T>(4) / static_cast<T>(3)) * std::numbers::pi_v<T>;
193
194 hilet U = oneThird * acos(((static_cast<T>(3) * q) / (static_cast<T>(2) * p)) * sqrt(static_cast<T>(-3) / p));
195 hilet V = static_cast<T>(2) * sqrt(-oneThird * p);
196
197 hilet t0 = V * cos(U);
198 hilet t1 = V * cos(U - pi2_3);
199 hilet t2 = V * cos(U - pi4_3);
200 return {t0, t1, t2};
201}
202
203template<typename T>
204hi_force_inline results<T, 3> solveDepressedCubicCardano(T const& p, T const& q, T const& D) noexcept
205{
206 hilet sqrtD = sqrt(D);
207 hilet minusHalfQ = static_cast<T>(-0.5) * q;
208 hilet v = cbrt(minusHalfQ + sqrtD);
209 hilet w = cbrt(minusHalfQ - sqrtD);
210 return {v + w};
211}
212
229template<typename T>
230hi_force_inline results<T, 3> solveDepressedCubic(T const& p, T const& q) noexcept
231{
232 constexpr T oneForth = static_cast<T>(1) / static_cast<T>(4);
233 constexpr T oneTwentySeventh = static_cast<T>(1) / static_cast<T>(27);
234
235 if (p == 0.0 && q == 0.0) {
236 return {static_cast<T>(0)};
237
238 } else {
239 hilet D = oneForth * q * q + oneTwentySeventh * p * p * p;
240
241 if (D < 0 && p != 0.0) {
242 // Has three real roots.
243 return solveDepressedCubicTrig(p, q);
244
245 } else if (D == 0 && p != 0.0) {
246 // Has two real roots, or maybe one root
247 hilet t0 = (static_cast<T>(3) * q) / p;
248 hilet t1 = (static_cast<T>(-3) * q) / (static_cast<T>(2) * p);
249 return {t0, t1, t1};
250
251 } else {
252 // Has one real root.
253 return solveDepressedCubicCardano(p, q, D);
254 }
255 }
256}
257
266template<typename T>
267hi_force_inline constexpr results<T, 3> solvePolynomial(T const& a, T const& b, T const& c, T const& d) noexcept
268{
269 if (a == 0) {
270 return solvePolynomial(b, c, d);
271
272 } else {
273 hilet p = (static_cast<T>(3) * a * c - b * b) / (static_cast<T>(3) * a * a);
274 hilet q = (static_cast<T>(2) * b * b * b - static_cast<T>(9) * a * b * c + static_cast<T>(27) * a * a * d) /
275 (static_cast<T>(27) * a * a * a);
276
277 hilet r = solveDepressedCubic(p, q);
278
279 hilet b_3a = b / (static_cast<T>(3) * a);
280
281 return r - b_3a;
282 }
283}
284
285} // namespace hi::inline v1
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:199
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
hi_force_inline results< T, 3 > solveDepressedCubicTrig(T const &p, T const &q) noexcept
Definition polynomial.hpp:188
hi_force_inline constexpr results< T, 1 > solvePolynomial(T const &a, T const &b) noexcept
Definition polynomial.hpp:141
hi_force_inline results< T, 3 > solveDepressedCubic(T const &p, T const &q) noexcept
Definition polynomial.hpp:230
Definition polynomial.hpp:14