提问人:123iamking 提问时间:5/19/2022 最后编辑:John Kugelman123iamking 更新时间:5/25/2022 访问量:237
检查三次方程的根是否复数?
Check if root of cubic equation is complex or not?
问:
我使用这个立方根实现。
我有等式#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 个复数根应用于方程,它返回非零结果(失败);将 3 个非复数根应用于方程,它返回零结果(通过)。
但是在某些情况下,我将 3 复数根和 3 非复数根应用于方程(例如),它返回非零(失败)。47 x³ +7 x² -52 x + 0 = 0
我认为导致此问题的原因是因为以下代码:
/// <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 不够怎么办。还是解决这个问题的正确方法?
所以我想问,有没有更好的方法来判断根是否复杂?
答:
谢谢马克·迪金森。
所以根据维基百科:
delta > 0:立方体有三个不同的实根
delta < 0:立方有一个实根和两个非实复数 共轭根。
三角洲 D = (B*B - 4*A*A*A)/(-27*a*a)
我的理想是:
增量> 0:删除所有 3 根的虚数。
增量< 0:找到真正的根,然后删除其虚部(如果有) (以确保它是真实的)。保持其他 2 根不变。现在我 有 2 个想法来找到真正的根源:
理想 #1
从理论上讲,实根应该有 imaginary = 0,但由于浮点精度,imaginary 可能会稍微偏离 0(例如,imaginary = 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 个根 ({real, imaginary}),则上面的代码可能是错误的,如下所示:
{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
看看 3 个根是如何计算的:
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)
-53 x³ + 6 x² + 14 x - 54 = 0
)
我不知道数学是否可以证明这样的事情: 虽然:如果 x3 是实数,否则 x1 是实数?delta < 0
B < 0
因此,在我得到更好的想法之前,我将只使用想法#1。
评论
B
delta < 0
B < 0
x3 is real
x1 is real
B<0
x1 is real
下一个:如何最有效地缩放和设置十进制精度
评论
D = (B*B - 4*A*A*A)/(-27*a*a)