Exemple #1
0
        public static double[] Solve(double c, double d)
        {
            if (d < 0)
            {
                return(Solve(c, -d).Reverse().Select(x => - x).ToArray());
            }
            // 3重解の場合 (c = d = 0) を含む
            if (d == 0)
            {
                return c >= 0 ? new[] { 0D }
            }
            : new[] { -Sqrt(-c), 0D, Sqrt(-c) };

            // この式では誤差が大きくなることがあります。
            var det3 = -4 * c * c * c - 27 * d * d;

            // 重解の場合
            if (det3.EqualsNearly(0, 8))
            {
                return new[] { -2 * Sqrt(-c / 3), Sqrt(-c / 3) }
            }
            ;

            // 負の実数解
            var x1 = SolveNegative();

            if (det3 < 0)
            {
                return new[] { x1 }
            }
            ;

            // f(x) = (x - x_1) (x^2 + x_1 x + x_1^2 + c)
            var sqrt_det2 = Sqrt(-3 * x1 * x1 - 4 * c);

            return(new[] { x1, (-x1 - sqrt_det2) / 2, (-x1 + sqrt_det2) / 2 });

            double SolveNegative()
            {
                var f = CubicEquation1.CreateFunction(c, d);

                var f1 = CubicEquation1.CreateDerivative(c);
                var x0 = -1D;

                while (f(x0) > 0)
                {
                    x0 *= 2;
                }
                return(NewtonMethod.Solve(f, f1, x0));
            }
        }
    }
}
Exemple #2
0
        public static double[] Solve(double c, double d)
        {
            if (d < 0)
            {
                return(Solve(c, -d).Reverse().Select(x => - x).ToArray());
            }
            // 自明解
            if (d == 0 && c >= 0)
            {
                return new[] { 0D }
            }
            ;

            // 負の実数解
            var x1 = SolveNegative();
            // f(x) = (x - x_1) (x^2 + x_1 x + x_1^2 + c)
            var det = -3 * x1 * x1 - 4 * c;

            if (det < 0)
            {
                return new[] { x1 }
            }
            ;
            if (det == 0)
            {
                return new[] { x1, -x1 / 2 }
            }
            ;
            return(new[] { x1, (-x1 - Sqrt(det)) / 2, (-x1 + Sqrt(det)) / 2 });

            double SolveNegative()
            {
                var f = CubicEquation1.CreateFunction(c, d);

                var f1 = CubicEquation1.CreateDerivative(c);
                var x0 = -1D;

                while (f(x0) > 0)
                {
                    x0 *= 2;
                }
                return(NewtonMethod.Solve(f, f1, x0));
            }
        }
    }
}
        public void Solve_2()
        {
            void Test(double c, double d)
            {
                var actual = target2(c, d);
                var det    = -4 * c * c * c - 27 * d * d;

                Assert.AreEqual(c == 0 & d == 0 || det < 0 ? 1 : det == 0 ? 2 : 3, actual.Length);

                var f = CubicEquation1.CreateFunction(c, d);

                foreach (var x in actual)
                {
                    Assert2.AreNearlyEqual(0, f(x));
                }
            }

            for (int c = -100; c <= 100; c++)
            {
                for (int d = 0; d <= 100; d++)
                {
                    Test(c, d);
                }
            }
            for (int c1 = 1; c1 <= 20; c1++)
            {
                for (double c2 = -20; c2 <= 20; c2++)
                {
                    for (int d1 = 1; d1 <= 20; d1++)
                    {
                        for (double d2 = -20; d2 <= 20; d2++)
                        {
                            Test(c2 / c1, d2 / d1);
                        }
                    }
                }
            }
        }
        public void Solve_1()
        {
            void Test(double a, double b, double c, double d)
            {
                var actual = target1(a, b, c, d);

                var f = CubicEquation1.CreateFunction(a, b, c, d);

                foreach (var x in actual)
                {
                    Assert2.AreNearlyEqual(0, f(x), -9);
                }
            }

            // A case with error for the determinant.
            Test(20, 8, 0, 0);
            Test(6, 47, 0, 0);
            Test(5, 33, 0, 0);
            Test(2, 49, 0, 0);
            Test(5, 50, -6, 5);

            for (int a = -15; a <= 15; a++)
            {
                if (a != 0)
                {
                    for (int b = -15; b <= 15; b++)
                    {
                        for (int c = -15; c <= 15; c++)
                        {
                            for (int d = -15; d <= 15; d++)
                            {
                                Test(a, b, c, d);
                            }
                        }
                    }
                }
            }
        }