| @@ -1,25 +1,27 @@ | |||
| // | |||
| // Lol Engine | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://www.wtfpl.net/ for more details. | |||
| // Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net> | |||
| // | |||
| // Lol Engine is free software. It comes without any warranty, to | |||
| // the extent permitted by applicable law. You can redistribute it | |||
| // and/or modify it under the terms of the Do What the Fuck You Want | |||
| // to Public License, Version 2, as published by the WTFPL Task Force. | |||
| // See http://www.wtfpl.net/ for more details. | |||
| // | |||
| #pragma once | |||
| // | |||
| // The polynomial class | |||
| // -------------------- | |||
| // | |||
| // ———————————————————— | |||
| // The data structure is a simple dynamic array of scalars, with the | |||
| // added guarantee that the leading coefficient is always non-zero. | |||
| // | |||
| #include <functional> | |||
| #include <lol/base/features.h> | |||
| #include <tuple> // std::tuple | |||
| #include <cassert> // assert() | |||
| namespace lol | |||
| { | |||
| @@ -33,7 +35,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| /* A constant polynomial */ | |||
| explicit inline polynomial(T const &a) | |||
| { | |||
| m_coefficients.push(a); | |||
| m_coefficients.push_back(a); | |||
| reduce_degree(); | |||
| } | |||
| @@ -41,7 +43,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| explicit polynomial(std::initializer_list<T> const &init) | |||
| { | |||
| for (auto a : init) | |||
| m_coefficients.push(a); | |||
| m_coefficients.push_back(a); | |||
| reduce_degree(); | |||
| } | |||
| @@ -50,7 +52,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| static polynomial<T> chebyshev(int n) | |||
| { | |||
| /* Use T0(x) = 1, T1(x) = x, Tn(x) = 2 x Tn-1(x) - Tn-2(x) */ | |||
| std::function<int64_t (int, int)> coeff = [&](int i, int j) | |||
| auto coeff = [&](int i, int j) -> int64_t | |||
| { | |||
| if (i > j || i < 0 || ((j ^ i) & 1)) | |||
| return (int64_t)0; | |||
| @@ -61,7 +63,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| polynomial<T> ret; | |||
| for (int k = 0; k <= n; ++k) | |||
| ret.m_coefficients.push(T(coeff(k, n))); | |||
| ret.m_coefficients.push_back(T(coeff(k, n))); | |||
| return ret; | |||
| } | |||
| @@ -69,19 +71,19 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| * degree -1 on purpose. */ | |||
| inline int degree() const | |||
| { | |||
| return (int)m_coefficients.count() - 1; | |||
| return (int)m_coefficients.size() - 1; | |||
| } | |||
| /* Set one of the polynomial’s coefficients */ | |||
| void set(int n, T const &a) | |||
| { | |||
| ASSERT(n >= 0); | |||
| assert(n >= 0); | |||
| if (n > degree() && !a) | |||
| return; | |||
| while (n > degree()) | |||
| m_coefficients.push(T(0)); | |||
| m_coefficients.push_back(T(0)); | |||
| m_coefficients[n] = a; | |||
| reduce_degree(); | |||
| @@ -103,27 +105,26 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| /* No need to reduce the degree after deriving. */ | |||
| polynomial<T> ret; | |||
| for (int i = 1; i <= degree(); ++i) | |||
| ret.m_coefficients.push(m_coefficients[i] * T(i)); | |||
| ret.m_coefficients.push_back(m_coefficients[i] * T(i)); | |||
| return ret; | |||
| } | |||
| array<T> roots() const | |||
| std::vector<T> roots() const | |||
| { | |||
| /* For now we can only solve polynomials of degrees 0, 1, 2 or 3. */ | |||
| ASSERT(degree() >= 0 && degree() <= 3, | |||
| "roots() called on polynomial of degree %d", degree()); | |||
| assert(degree() >= 0 && degree() <= 3); | |||
| if (degree() == 0) | |||
| { | |||
| /* p(x) = a > 0 */ | |||
| return array<T> {}; | |||
| return {}; | |||
| } | |||
| else if (degree() == 1) | |||
| { | |||
| /* p(x) = ax + b */ | |||
| T const &a = m_coefficients[1]; | |||
| T const &b = m_coefficients[0]; | |||
| return array<T> { -b / a }; | |||
| return { -b / a }; | |||
| } | |||
| else if (degree() == 2) | |||
| { | |||
| @@ -137,16 +138,16 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| if (delta < T(0)) | |||
| { | |||
| return array<T> {}; | |||
| return {}; | |||
| } | |||
| else if (delta > T(0)) | |||
| { | |||
| T const sqrt_delta = sqrt(delta); | |||
| return array<T> { -k - sqrt_delta, -k + sqrt_delta }; | |||
| return { -k - sqrt_delta, -k + sqrt_delta }; | |||
| } | |||
| else | |||
| { | |||
| return array<T> { -k }; | |||
| return { -k }; | |||
| } | |||
| } | |||
| else if (degree() == 3) | |||
| @@ -227,33 +228,33 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| if (a == d && b == c && b == T(3)*a) // triple solution | |||
| { | |||
| return array<T> { solutions[0] - k }; | |||
| return { solutions[0] - k }; | |||
| } | |||
| // if root of the derivative is also root of the current polynomial, we have a double root. | |||
| for (auto root : (polynomial<T>{ c, T(2) * b, T(3) * a }).roots()) | |||
| { | |||
| if (eval(root) == T(0)) | |||
| return array<T> { (solutions[0] + solutions[2]) / T(2) - k, | |||
| solutions[1] - k }; | |||
| return { (solutions[0] + solutions[2]) / T(2) - k, | |||
| solutions[1] - k }; | |||
| } | |||
| // we have 3 or 1 root depending on delta sign | |||
| if (delta > 0) | |||
| { | |||
| return array<T> { solutions[0] - k }; | |||
| return { solutions[0] - k }; | |||
| } | |||
| else // if (delta < 0) 3 real solutions | |||
| { | |||
| return array<T> { solutions[0] - k, | |||
| solutions[1] - k, | |||
| solutions[2] - k }; | |||
| return { solutions[0] - k, | |||
| solutions[1] - k, | |||
| solutions[2] - k }; | |||
| } | |||
| } | |||
| /* It is an error to reach this point. */ | |||
| ASSERT(false); | |||
| return array<T> {}; | |||
| assert(false); | |||
| return {}; | |||
| } | |||
| /* Access individual coefficients. This is read-only and returns a | |||
| @@ -296,7 +297,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| { | |||
| polynomial<T> ret; | |||
| for (auto a : m_coefficients) | |||
| ret.m_coefficients.push(-a); | |||
| ret.m_coefficients.push_back(-a); | |||
| return ret; | |||
| } | |||
| @@ -309,7 +310,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| m_coefficients[i] += p[i]; | |||
| for (int i = min_degree + 1; i <= p.degree(); ++i) | |||
| m_coefficients.push(p[i]); | |||
| m_coefficients.push_back(p[i]); | |||
| reduce_degree(); | |||
| return *this; | |||
| @@ -371,7 +372,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| { | |||
| int n = p.degree() + q.degree(); | |||
| for (int i = 0; i <= n; ++i) | |||
| ret.m_coefficients.push(T(0)); | |||
| ret.m_coefficients.push_back(T(0)); | |||
| for (int i = 0; i <= p.degree(); ++i) | |||
| for (int j = 0; j <= q.degree(); ++j) | |||
| @@ -385,13 +386,13 @@ struct LOL_ATTR_NODISCARD polynomial | |||
| /* Divide a polynomial by another one. There is no /= variant because | |||
| * the return value contains both the quotient and the remainder. */ | |||
| tuple<polynomial<T>, polynomial<T>> operator /(polynomial<T> p) const | |||
| std::tuple<polynomial<T>, polynomial<T>> operator /(polynomial<T> p) const | |||
| { | |||
| ASSERT(p.degree() >= 0); | |||
| assert(p.degree() >= 0); | |||
| tuple<polynomial<T>, polynomial<T>> ret; | |||
| polynomial<T> "ient = ret.m1; | |||
| polynomial<T> &remainder = ret.m2; | |||
| std::tuple<polynomial<T>, polynomial<T>> ret; | |||
| polynomial<T> "ient = std::get<0>(ret); | |||
| polynomial<T> &remainder = std::get<1>(ret); | |||
| remainder = *this / p.leading(); | |||
| p /= p.leading(); | |||
| @@ -416,7 +417,7 @@ private: | |||
| } | |||
| /* The polynomial coefficients */ | |||
| array<T> m_coefficients; | |||
| std::vector<T> m_coefficients; | |||
| }; | |||
| template<typename T> | |||