检查三次方程的根是否复杂?
Check if root of cubic equation is complex or not?
我使用 this Cubic root 实现。
我有等式#1:
x³ -2 x² -5 x + 6 = 0
它给了我 3 个复根({实数,虚数}):
{-2, 7.4014868308343765E-17}
{1 , -2.9605947323337506E-16}
{3 , 2.9605947323337506E-16}
但实际上,正确的结果应该是3个非复根:-2,1,3。
对于这种情况,我可以通过以下方式进行测试:对方程应用 3 个复根,它 returns 非零结果(失败);对等式应用 3 个非复数根,它 return 的结果为零(通过)。
但在某些情况下,我将 3 复根和 3 非复根应用于方程(例如 47 x³ +7 x² -52 x + 0 = 0
),它 return 非零(失败)。
我认为导致这个问题的原因是这段代码:
/// <summary>
/// Evaluate all cubic roots of this <c>Complex</c>.
/// </summary>
public static (Complex, Complex, Complex) CubicRoots(this Complex complex)
{
var r = Math.Pow(complex.Magnitude, 1d/3d);
var theta = complex.Phase/3;
const double shift = Constants.Pi2/3;
return (Complex.FromPolarCoordinates(r, theta),
Complex.FromPolarCoordinates(r, theta + shift),
Complex.FromPolarCoordinates(r, theta - shift));
}
我知道浮点值在计算 (~1E-15) 时可能会失去精度,但问题是虚部需要确定它是零还是非零以判断它是否为复数。
我不能告诉我的应用程序的用户:“嘿用户,如果你看到虚部足够接近 0,你可以自己决定根不是复数”。
目前我用这个方法检查:
const int TOLERATE = 15;
bool isRemoveImaginary = System.Math.Round(root.Imaginary, TOLERATE) == 0; //Remove imaginary if it's too close to zero
但是我不知道这个方法是否合适,如果TOLERATE = 15不够用怎么办。还是解决这个问题的正确方法?
所以我想问一下,有没有更好的方法来判断根是否复?
谢谢。
所以根据Wikipedia:
delta > 0: the cubic has three distinct real roots
delta < 0: the cubic has one real root and two non-real complex
conjugate roots.
deltaD = (B*B - 4*A*A*A)/(-27*a*a)
我的理想是:
delta > 0: 去掉3根的所有虚数
delta < 0: 求实根然后去掉虚部
(以确保它是真实的)。保持其他 2 个根不变。现在我
有 2 个想法 来找到真正的根:
理想#1
理论上实根应该虚数=0,但由于浮点精度,虚数可以稍微偏离0(例如虚数=1E-15而不是0)。所以思路是:3个根中的第1个实根应该有最接近0的虚数。
代码:
NumComplex[] arrRoot = { x1, x2, x3 };
if (delta > 0)
{
for (var idxRoot = 0; idxRoot < arrRoot.Length; ++idxRoot)
arrRoot[idxRoot] = arrRoot[idxRoot].RemoveImaginary();
}
else
{
//The root with imaginary closest to 0 should be the real root,
//the other two should be non-real.
var realRootIdx = 0;
var absClosest = double.MaxValue;
double abs;
for (var idxRoot = 0; idxRoot < arrRoot.Length; ++idxRoot)
{
abs = System.Math.Abs(arrRoot[idxRoot].GetImaginary());
if (abs < absClosest)
{
absClosest = abs;
realRootIdx = idxRoot;
}
}
arrRoot[realRootIdx] = arrRoot[realRootIdx].RemoveImaginary();
}
如果有 3 个根({实数,虚数}),上面的代码可能是错误的:
{7, -1E-99}
{3, 1E-15}//1E-15 caused by floating point precision, 1E-15 should be 0
{7, 1E-99}//My code will mistake this because this is closer to 0 than 1E-15.
如果这种情况真的发生在现实生活中,我会想出一个更好的方法来挑选真正的根。
想法 #2
看看如何 the 3 roots calculated:
x1 = FromPolarCoordinates(r, theta);
x2 = FromPolarCoordinates(r, theta + shift);
x3 = FromPolarCoordinates(r, theta - shift);
3 个根具有以下形式(通过测试知道,未通过数学证明):
x1 = { A }
x2 = { B, C }
x3 = { B, -C }
用数学知识证明3个根中哪一个是真根
试验 #1:也许根 x1 = FromPolarCoordinates(r, theta)
总是真实的? (failed) untrue 因为下面的案例证明猜测是错误的:-53 x³ + 6 x² + 14 x - 54 = 0
(感谢)
我不知道数学是否可以证明类似的东西:while delta < 0
: if B < 0
then x3 is real, else x1 is real?
所以在我有更好的想法之前,我将只使用想法 #1。
我使用 this Cubic root 实现。
我有等式#1:
x³ -2 x² -5 x + 6 = 0
它给了我 3 个复根({实数,虚数}):
{-2, 7.4014868308343765E-17}
{1 , -2.9605947323337506E-16}
{3 , 2.9605947323337506E-16}
但实际上,正确的结果应该是3个非复根:-2,1,3。
对于这种情况,我可以通过以下方式进行测试:对方程应用 3 个复根,它 returns 非零结果(失败);对等式应用 3 个非复数根,它 return 的结果为零(通过)。
但在某些情况下,我将 3 复根和 3 非复根应用于方程(例如 47 x³ +7 x² -52 x + 0 = 0
),它 return 非零(失败)。
我认为导致这个问题的原因是这段代码:
/// <summary>
/// Evaluate all cubic roots of this <c>Complex</c>.
/// </summary>
public static (Complex, Complex, Complex) CubicRoots(this Complex complex)
{
var r = Math.Pow(complex.Magnitude, 1d/3d);
var theta = complex.Phase/3;
const double shift = Constants.Pi2/3;
return (Complex.FromPolarCoordinates(r, theta),
Complex.FromPolarCoordinates(r, theta + shift),
Complex.FromPolarCoordinates(r, theta - shift));
}
我知道浮点值在计算 (~1E-15) 时可能会失去精度,但问题是虚部需要确定它是零还是非零以判断它是否为复数。
我不能告诉我的应用程序的用户:“嘿用户,如果你看到虚部足够接近 0,你可以自己决定根不是复数”。
目前我用这个方法检查:
const int TOLERATE = 15;
bool isRemoveImaginary = System.Math.Round(root.Imaginary, TOLERATE) == 0; //Remove imaginary if it's too close to zero
但是我不知道这个方法是否合适,如果TOLERATE = 15不够用怎么办。还是解决这个问题的正确方法?
所以我想问一下,有没有更好的方法来判断根是否复?
谢谢
所以根据Wikipedia:
delta > 0: the cubic has three distinct real roots
delta < 0: the cubic has one real root and two non-real complex conjugate roots.
deltaD = (B*B - 4*A*A*A)/(-27*a*a)
我的理想是:
delta > 0: 去掉3根的所有虚数
delta < 0: 求实根然后去掉虚部 (以确保它是真实的)。保持其他 2 个根不变。现在我 有 2 个想法 来找到真正的根:
理想#1
理论上实根应该虚数=0,但由于浮点精度,虚数可以稍微偏离0(例如虚数=1E-15而不是0)。所以思路是:3个根中的第1个实根应该有最接近0的虚数。
代码:
NumComplex[] arrRoot = { x1, x2, x3 };
if (delta > 0)
{
for (var idxRoot = 0; idxRoot < arrRoot.Length; ++idxRoot)
arrRoot[idxRoot] = arrRoot[idxRoot].RemoveImaginary();
}
else
{
//The root with imaginary closest to 0 should be the real root,
//the other two should be non-real.
var realRootIdx = 0;
var absClosest = double.MaxValue;
double abs;
for (var idxRoot = 0; idxRoot < arrRoot.Length; ++idxRoot)
{
abs = System.Math.Abs(arrRoot[idxRoot].GetImaginary());
if (abs < absClosest)
{
absClosest = abs;
realRootIdx = idxRoot;
}
}
arrRoot[realRootIdx] = arrRoot[realRootIdx].RemoveImaginary();
}
如果有 3 个根({实数,虚数}),上面的代码可能是错误的:
{7, -1E-99}
{3, 1E-15}//1E-15 caused by floating point precision, 1E-15 should be 0
{7, 1E-99}//My code will mistake this because this is closer to 0 than 1E-15.
如果这种情况真的发生在现实生活中,我会想出一个更好的方法来挑选真正的根。
想法 #2
看看如何 the 3 roots calculated:
x1 = FromPolarCoordinates(r, theta);
x2 = FromPolarCoordinates(r, theta + shift);
x3 = FromPolarCoordinates(r, theta - shift);
3 个根具有以下形式(通过测试知道,未通过数学证明):
x1 = { A }
x2 = { B, C }
x3 = { B, -C }
用数学知识证明3个根中哪一个是真根
试验 #1:也许根 x1 = FromPolarCoordinates(r, theta)
总是真实的? (failed) untrue 因为下面的案例证明猜测是错误的:-53 x³ + 6 x² + 14 x - 54 = 0
(感谢
我不知道数学是否可以证明类似的东西:while delta < 0
: if B < 0
then x3 is real, else x1 is real?
所以在我有更好的想法之前,我将只使用想法 #1。