43TEST(PolynomialTest, SolveQuadratic) {
44 for (
unsigned i = 0; i < 1000; ++i) {
45 Coord x1 = g_random_double_range(-100, 100);
46 Coord x2 = g_random_double_range(-100, 100);
48 Coord a = g_random_double_range(-10, 10);
49 Coord b = -a * (x1 + x2);
54 EXPECT_EQ(
result.size(), 2u);
56 EXPECT_FLOAT_EQ(
result[0], x1);
57 EXPECT_FLOAT_EQ(
result[1], x2);
59 EXPECT_FLOAT_EQ(
result[0], x2);
60 EXPECT_FLOAT_EQ(
result[1], x1);
65TEST(PolynomialTest, SolvePathologicalQuadratic) {
69 ASSERT_EQ(r.size(), 2u);
70 EXPECT_FLOAT_EQ(r[0], 1e-9);
71 EXPECT_FLOAT_EQ(r[1], 1e9);
74 ASSERT_EQ(r.size(), 2u);
75 EXPECT_FLOAT_EQ(r[0], 1.999);
76 EXPECT_FLOAT_EQ(r[1], 2.001);
79 ASSERT_EQ(r.size(), 2u);
80 EXPECT_FLOAT_EQ(r[0], -2);
81 EXPECT_FLOAT_EQ(r[1], 2);
84 ASSERT_EQ(r.size(), 2u);
85 EXPECT_FLOAT_EQ(r[0], -4);
86 EXPECT_FLOAT_EQ(r[1], 4);
89 ASSERT_EQ(r.size(), 2u);
90 EXPECT_FLOAT_EQ(r[0], -10);
91 EXPECT_FLOAT_EQ(r[1], 10);
94TEST(PolynomialTest, SolveCubic) {
95 for (
unsigned i = 0; i < 1000; ++i) {
96 Coord x1 = g_random_double_range(-100, 100);
97 Coord x2 = g_random_double_range(-100, 100);
98 Coord x3 = g_random_double_range(-100, 100);
100 Coord a = g_random_double_range(-10, 10);
101 Coord b = -a * (x1 + x2 + x3);
102 Coord c = a * (x1*x2 + x2*x3 + x1*x3);
103 Coord d = -a * x1 * x2 * x3;
106 std::vector<Coord> x(3); x[0] = x1; x[1] = x2; x[2] = x3;
107 std::sort(x.begin(), x.end());
109 ASSERT_EQ(
result.size(), 3u);
110 EXPECT_FLOAT_EQ(
result[0], x[0]);
111 EXPECT_FLOAT_EQ(
result[1], x[1]);
112 EXPECT_FLOAT_EQ(
result[2], x[2]);
117 std::vector<Coord> r1 =
solve_cubic(1, -2, 7, -14);
118 EXPECT_EQ(r1.size(), 1u);
119 EXPECT_FLOAT_EQ(r1[0], 2);
123 ASSERT_EQ(r2.size(), 3u);
124 EXPECT_FLOAT_EQ(r2[0], -1);
125 EXPECT_FLOAT_EQ(r2[1], -1);
126 EXPECT_FLOAT_EQ(r2[2], 2);
130TEST(PolynomialTest, SolveQuartic_4_roots)
132 g_random_set_seed(0xB737A380);
133 double const eps = 4e-6;
134 std::array<Coord, 4>
roots;
136 for (
size_t _ = 0; _ < 10'000; ++_) {
139 root = g_random_double_range(-100, 100);
146 a = g_random_double_range(-100, 100);
164 auto const recovered =
solve_quartic(a, -a * sym1, a * sym2, -a * sym3, a * sym4);
165 ASSERT_EQ(recovered.size(), 4);
166 for (
size_t i = 0; i < 4; ++i) {
173TEST(PolynomialTest, SolveQuartic_Evaluate)
175 g_random_set_seed(0xB737A380);
176 double const eps = 3e-6;
177 for (
size_t _ = 0; _ < 10'000; ++_) {
179 for (
size_t i = 0; i < 4; ++i) {
180 quartic.push_back(g_random_double_range(-100, 100));
195 while (std::abs(a) < 1e-3) {
196 a = g_random_double_range(-10, 10);
198 double b = g_random_double_range(-10, 10);
199 double c = g_random_double_range(1, 100);
200 int sign = 2 * g_random_boolean() - 1;
209TEST(PolynomialTest, SolveQuartic_2_roots)
211 g_random_set_seed(0xB737A380);
212 double const eps = 1e-9;
214 std::array<Coord, 2>
roots;
215 for (
size_t _ = 0; _ < 10'000; ++_) {
218 root = g_random_double_range(-100, 100);
229 comp[1] - comp[0] * sym1,
230 comp[2] + sym2 * comp[0] - comp[1] * sym1,
231 comp[1] * sym2 - comp[2] * sym1,
233 ASSERT_EQ(recovered.size(), 2);
234 for (
size_t i = 0; i < 2; ++i) {
241TEST(PolynomialTest, SolveQuartic_DoubleRoots)
243 g_random_set_seed(123456789);
244 double const eps = 4e-5;
245 std::array<Coord, 4>
roots;
247 for (
size_t _ = 0; _ < 1000; ++_) {
249 for (
size_t i = 0; i < 3; ++i) {
250 roots[i] = g_random_double_range(-100, 100);
257 a = g_random_double_range(-100, 100);
275 auto const recovered =
solve_quartic(a, -a * sym1, a * sym2, -a * sym3, a * sym4);
276 for (
Coord found : recovered) {
277 double best_relative_error =
infinity();
279 best_relative_error = std::min(best_relative_error, std::abs((found -
root) /
root));
281 EXPECT_LE(best_relative_error, eps);
287TEST(PolynomialTest, SolveQuartic_0_roots)
289 g_random_set_seed(0xA380B737);
290 for (
size_t _ = 0; _ < 10'000; ++_) {
298 a1 * c2 + b1 * b2 + c1 * a2,
301 EXPECT_TRUE(recovered.empty());
306TEST(PolynomialTest, SolveQuartic_degenerate)
308 g_random_set_seed(0xB737A380);
309 for (
size_t _ = 0; _ < 10'000; ++_) {
310 auto const b = g_random_double_range(-100, 100);
311 auto const c = g_random_double_range(-100, 100);
312 auto const d = g_random_double_range(-100, 100);
313 auto const e = g_random_double_range(-100, 100);
318 EXPECT_EQ(degen1, as_cubic);
323 EXPECT_EQ(degen2, as_quadratic);
326 while (std::abs(a) < 1e-3) {
327 a = g_random_double_range(-100, 100);
333 cubic_and_zero.push_back(0);
334 std::sort(cubic_and_zero.begin(), cubic_and_zero.end());
335 EXPECT_EQ(degen3, cubic_and_zero);
340 quad_and_zero.push_back(0);
341 quad_and_zero.push_back(0);
342 std::sort(quad_and_zero.begin(), quad_and_zero.end());
343 EXPECT_EQ(degen4, quad_and_zero);
Polynomial in canonical (monomial) basis.
constexpr Coord infinity()
Get a value representing infinity.
double Coord
Floating point type used to store coordinates.
Various utility functions.
std::vector< Coord > solve_quartic(Coord a, Coord b, Coord c, Coord d, Coord e)
Analytically solve quartic equation.
static float sign(double number)
Returns +1 for positive numbers, -1 for negative numbers, and 0 otherwise.
std::vector< Coord > solve_quadratic(Coord a, Coord b, Coord c)
Analytically solve quadratic equation.
std::vector< Coord > solve_cubic(Coord a, Coord b, Coord c, Coord d)
Analytically solve cubic equation.
std::vector< double > roots(SBasis const &s)
TEST(AffineTest, Equality)
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
static std::array< Coord, 3 > get_random_irreducible_quadratic()
Return the coefficients of a random irreducible quadratic polynomial.
Polynomial in canonical (monomial) basis.