| @@ -14,6 +14,9 @@ | |||||
| // The polynomial class | // 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 <functional> | ||||
| @@ -105,50 +108,56 @@ struct polynomial | |||||
| array<T> roots() const | array<T> roots() const | ||||
| { | { | ||||
| ASSERT(degree() >= 0, "roots() called on the null polynomial"); | |||||
| /* For now we can only solve polynomials of degrees 0, 1 or 2. */ | |||||
| ASSERT(degree() >= 0 && degree() <= 2, | |||||
| "roots() called on polynomial of degree %d", degree()); | |||||
| if (degree() == 0) | if (degree() == 0) | ||||
| { | { | ||||
| /* p(x) = a > 0 */ | |||||
| return array<T> {}; | |||||
| /* p(x) = a > 0 */ | |||||
| return array<T> {}; | |||||
| } | } | ||||
| else if (degree() == 1) | 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 }; | |||||
| /* p(x) = ax + b */ | |||||
| T const &a = m_coefficients[1]; | |||||
| T const &b = m_coefficients[0]; | |||||
| return array<T> { -b / a }; | |||||
| } | } | ||||
| else if (degree() == 2) | else if (degree() == 2) | ||||
| { | { | ||||
| /* p(x) = ax² + bx + c */ | |||||
| T const &a = m_coefficients[2]; | |||||
| T const &b = m_coefficients[1]; | |||||
| T const &c = m_coefficients[0]; | |||||
| /* p(x) = ax² + bx + c */ | |||||
| T const &a = m_coefficients[2]; | |||||
| T const &b = m_coefficients[1]; | |||||
| T const &c = m_coefficients[0]; | |||||
| T const k = b / (a + a); | |||||
| T const delta = k * k - c / a; | |||||
| T const k = b / (a + a); | |||||
| T const delta = k * k - c / a; | |||||
| if (delta < T(0)) | |||||
| { | |||||
| if (delta < T(0)) | |||||
| { | |||||
| return array<T> {}; | return array<T> {}; | ||||
| } | |||||
| else if (delta > T(0)) | |||||
| { | |||||
| } | |||||
| else if (delta > T(0)) | |||||
| { | |||||
| T const sqrt_delta = sqrt(delta); | T const sqrt_delta = sqrt(delta); | ||||
| return array<T> { -k - sqrt_delta, -k + sqrt_delta }; | return array<T> { -k - sqrt_delta, -k + sqrt_delta }; | ||||
| } | |||||
| else | |||||
| { | |||||
| } | |||||
| else | |||||
| { | |||||
| return array<T> { -k }; | return array<T> { -k }; | ||||
| } | |||||
| } | |||||
| } | } | ||||
| ASSERT(false, "roots() called on polynomial of degree %d > 2", | |||||
| degree()); | |||||
| /* It is an error to reach this point. */ | |||||
| ASSERT(false); | |||||
| return array<T> {}; | return array<T> {}; | ||||
| } | } | ||||
| /* Access individual coefficients. This is read-only and returns a | |||||
| * copy because we cannot let the user mess with the integrity of | |||||
| * the structure (i.e. the guarantee that the leading coefficient | |||||
| * remains non-zero). */ | |||||
| inline T operator[](ptrdiff_t n) const | inline T operator[](ptrdiff_t n) const | ||||
| { | { | ||||
| if (n < 0 || n > degree()) | if (n < 0 || n > degree()) | ||||
| @@ -157,11 +166,13 @@ struct polynomial | |||||
| return m_coefficients[n]; | return m_coefficients[n]; | ||||
| } | } | ||||
| /* Unary plus */ | |||||
| polynomial<T> operator +() const | polynomial<T> operator +() const | ||||
| { | { | ||||
| return *this; | return *this; | ||||
| } | } | ||||
| /* Unary minus */ | |||||
| polynomial<T> operator -() const | polynomial<T> operator -() const | ||||
| { | { | ||||
| polynomial<T> ret; | polynomial<T> ret; | ||||
| @@ -170,6 +181,7 @@ struct polynomial | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| /* Add two polynomials */ | |||||
| polynomial<T> &operator +=(polynomial<T> const &p) | polynomial<T> &operator +=(polynomial<T> const &p) | ||||
| { | { | ||||
| int min_degree = lol::min(p.degree(), degree()); | int min_degree = lol::min(p.degree(), degree()); | ||||
| @@ -189,6 +201,7 @@ struct polynomial | |||||
| return polynomial<T>(*this) += p; | return polynomial<T>(*this) += p; | ||||
| } | } | ||||
| /* Subtract two polynomials */ | |||||
| polynomial<T> &operator -=(polynomial<T> const &p) | polynomial<T> &operator -=(polynomial<T> const &p) | ||||
| { | { | ||||
| return *this += -p; | return *this += -p; | ||||
| @@ -199,6 +212,7 @@ struct polynomial | |||||
| return polynomial<T>(*this) += -p; | return polynomial<T>(*this) += -p; | ||||
| } | } | ||||
| /* Multiply polynomial by a scalar */ | |||||
| polynomial<T> &operator *=(T const &k) | polynomial<T> &operator *=(T const &k) | ||||
| { | { | ||||
| for (auto &a : m_coefficients) | for (auto &a : m_coefficients) | ||||
| @@ -212,6 +226,18 @@ struct polynomial | |||||
| return polynomial<T>(*this) *= k; | return polynomial<T>(*this) *= k; | ||||
| } | } | ||||
| /* Divide polynomial by a scalar */ | |||||
| polynomial<T> &operator /=(T const &k) | |||||
| { | |||||
| return *this *= (T(1) / k); | |||||
| } | |||||
| polynomial<T> operator /(T const &k) const | |||||
| { | |||||
| return *this * (T(1) / k); | |||||
| } | |||||
| /* Multiply polynomial by another polynomial */ | |||||
| polynomial<T> &operator *=(polynomial<T> const &p) | polynomial<T> &operator *=(polynomial<T> const &p) | ||||
| { | { | ||||
| return *this = *this * p; | return *this = *this * p; | ||||
| @@ -239,6 +265,7 @@ struct polynomial | |||||
| } | } | ||||
| private: | private: | ||||
| /* Enforce the non-zero leading coefficient rule. */ | |||||
| void reduce_degree() | void reduce_degree() | ||||
| { | { | ||||
| while (m_coefficients.Count() && m_coefficients.Last() == T(0)) | while (m_coefficients.Count() && m_coefficients.Last() == T(0)) | ||||