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