| #pragma once |
| |
| #ifndef TCG_POLY_OPS_H |
| #define TCG_POLY_OPS_H |
| |
| |
| #include "macros.h" |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| namespace tcg |
| { |
| |
| |
| namespace poly_ops |
| { |
| |
| |
| |
| |
| |
| template <typename Scalar> |
| Scalar evaluate( |
| const Scalar poly[], |
| int deg, |
| Scalar x) |
| { |
| |
| |
| Scalar value = poly[deg]; |
| for (int d = deg - 1; d >= 0; --d) |
| value = value * x + poly[d]; |
| |
| return value; |
| } |
| |
| |
| |
| |
| |
| |
| |
| template <typename Scalar> |
| void reduceDegree( |
| const Scalar poly[], |
| int °, |
| Scalar tolerance |
| ) |
| { |
| while ((deg > 0) && (std::abs(poly[deg]) < tolerance)) |
| --deg; |
| } |
| |
| |
| |
| |
| |
| |
| |
| template <typename A, typename B, typename C, int deg> |
| void add( |
| const A(&poly1)[deg], |
| const B(&poly2)[deg], |
| C(&result)[deg]) |
| { |
| for (int d = 0; d != deg; ++d) |
| result[d] = poly1[d] + poly2[d]; |
| } |
| |
| |
| |
| |
| |
| |
| |
| template <typename A, typename B, typename C, int deg> |
| void sub( |
| const A(&poly1)[deg], |
| const B(&poly2)[deg], |
| C(&result)[deg]) |
| { |
| for (int d = 0; d != deg; ++d) |
| result[d] = poly1[d] - poly2[d]; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename A, typename B, typename C, int deg1, int deg2, int degR> |
| void mul( |
| const A(&poly1)[deg1], |
| const B(&poly2)[deg2], |
| C(&result)[degR]) |
| { |
| TCG_STATIC_ASSERT(degR == deg1 + deg2 - 1); |
| |
| for (int a = 0; a != deg1; ++a) { |
| for (int b = 0; b != deg2; ++b) |
| result[a + b] += poly1[a] * poly2[b]; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename A, typename B, typename C, int deg1, int deg2, int degR> |
| void chain( |
| const A(&poly1)[deg1], |
| const B(&poly2)[deg2], |
| C(&result)[degR]) |
| { |
| for (int a = 0; a != deg1; ++a) { |
| B pow[degR][2] = {{}}; |
| |
| |
| { |
| std::copy(poly2, poly2 + deg2, pow[1]); |
| |
| for (int p = 1; p < a; ++p) |
| poly_mul(pow[p % 2], poly2, pow[(p + 1) % 2]); |
| } |
| |
| B(&pow_add) |
| [degR] = pow[a % 2]; |
| |
| |
| C addendum[degR]; |
| |
| for (int c = 0; c != degR; ++c) |
| addendum[c] = poly1[c] * pow_add[c]; |
| |
| poly_add(addendum, result); |
| } |
| } |
| |
| |
| |
| template <typename A, typename B, int deg, int degR> |
| void derivative( |
| const A(&poly)[deg], |
| B(&result)[degR]) |
| { |
| TCG_STATIC_ASSERT(degR == deg - 1); |
| |
| for (int c = 1; c != deg; ++c) |
| result[c - 1] = c * poly[c]; |
| } |
| |
| |
| |
| |
| |
| |
| |
| template <typename Scalar> |
| inline unsigned int solve_1( |
| Scalar c[2], |
| Scalar s[1], |
| Scalar tol = 0) |
| |
| { |
| if (std::abs(c[1]) <= tol) |
| return 0; |
| |
| s[0] = -c[0] / c[1]; |
| return 1; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename Scalar> |
| unsigned int solve_2( |
| Scalar c[3], |
| Scalar s[2], |
| Scalar tol = 0) |
| |
| { |
| if (std::abs(c[2]) <= tol) |
| return solve_1(c, s, tol); |
| |
| Scalar nc[2] = {c[0] / c[2], c[1] / (c[2] + c[2])}; |
| |
| Scalar delta = nc[1] * nc[1] - nc[0]; |
| if (delta < 0) |
| return 0; |
| |
| delta = sqrt(delta); |
| |
| s[0] = -delta - nc[1]; |
| s[1] = delta - nc[1]; |
| |
| return 2; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| template <typename Scalar> |
| unsigned int solve_3( |
| Scalar c[4], |
| Scalar s[3], |
| Scalar tol = 0) |
| |
| { |
| if (std::abs(c[3]) <= tol) |
| return solve_2(c, s, tol); |
| |
| Scalar nc[3] = {c[0] / c[3], c[1] / c[3], c[2] / c[3]}; |
| |
| Scalar b2 = nc[2] * nc[2]; |
| Scalar p = nc[1] - b2 / 3; |
| Scalar q = nc[2] * (b2 + b2 - 9 * nc[1]) / 27 + nc[0]; |
| Scalar p3 = p * p * p; |
| Scalar d = q * q + 4 * p3 / 27; |
| Scalar offset = -nc[2] / 3; |
| |
| if (d >= 0) { |
| |
| Scalar z = sqrt(d); |
| Scalar u = (-q + z) / 2; |
| Scalar v = (-q - z) / 2; |
| |
| u = (u < 0) ? -pow(-u, 1 / Scalar(3)) : pow(u, 1 / Scalar(3)); |
| v = (v < 0) ? -pow(-v, 1 / Scalar(3)) : pow(v, 1 / Scalar(3)); |
| |
| s[0] = offset + u + v; |
| return 1; |
| } |
| |
| assert(p3 < 0); |
| |
| Scalar u = sqrt(-p / Scalar(3)); |
| Scalar v = acos(-sqrt(-27 / p3) * q / Scalar(2)) / Scalar(3); |
| Scalar m = cos(v), n = sin(v) * 1.7320508075688772935274463415059; |
| |
| s[0] = offset - u * (n + m); |
| s[1] = offset + u * (n - m); |
| s[2] = offset + u * (m + m); |
| |
| assert(s[0] <= s[1] && s[1] <= s[2]); |
| |
| return 3; |
| } |
| } |
| } |
| |
| #endif // TCG_POLY_OPS_H |