复数显示为非常小的小数

Complex number displaying as incredibly small decimal

提问人:BigBoronto 提问时间:5/29/2023 最后编辑:Yakov GalkaBigBoronto 更新时间:5/29/2023 访问量:63

问:

正在使用 MathNet 库中的一种方法并尝试应用其立方根查找函数,但它输出令人难以置信的长小数,四舍五入似乎不会影响它们。

public static (Complex, Complex, Complex) FindCubic(double a, double b, double c, double d)
{
    double num = b * b - 3.0 * a * c;
    double num2 = 2.0 * b * b * b - 9.0 * a * b * c + 27.0 * a * a * d;
    double num3 = -1.0 / (3.0 * a);
    if ((num2 * num2 - 4.0 * num * num * num) / (-27.0 * a * a) == 0.0)
    {
        if (num == 0.0)
        {
            Complex complex = new Complex(num3 * b, 0.0);
            return (complex, complex, complex);
        }
        Complex complex2 = new Complex((9.0 * a * d - b * c) / (2.0 * num), 0.0);
        Complex item = new Complex((4.0 * a * b * c - 9.0 * a * a * d - b * b * b) / (a * num), 0.0);
        return (complex2, complex2, item);
    }
    (Complex, Complex, Complex) tuple = ((num == 0.0) ? new Complex(num2, 0.0).CubicRoots() : ((num2 + Complex.Sqrt(num2 * num2 - 4.0 * num * num * num)) / 2.0).CubicRoots());
    return (num3 * (b + tuple.Item1 + num / tuple.Item1), num3 * (b + tuple.Item2 + num / tuple.Item2), num3 * (b + tuple.Item3 + num / tuple.Item3));
}

上面的代码工作正常,但真的不确定如何缩短结果中的小数点。例如,如果输出在理论上应该是 (-1, 0)(在大多数计算器上确实显示这样),则它显示 (-1, -2.0354088784794536E-16),它接近 0,并且应该显示为 0。

Round(num3, 0) * (b + new Complex (Round(tuple.Item1.Real, 0), Round(tuple.Item1.Imaginary, 0)) + num / tuple.Item1)

有问题的舍入代码,因为您不能直接舍入复数。

在评论中解决:忘记了浮点不准确。

C# .NET 数学 浮点 MathNet-Numerics

评论

0赞 BigBoronto 5/29/2023
@YakovGalka使用 Math.Round 四舍五入到 0 会得到另一个混乱的小数。它确实是四舍五入的,只是不是 0。护理部分主要是因为它应该正好是 0。
0赞 BigBoronto 5/29/2023
@YakovGalka 其实那是我的错,忘记了整个浮点问题,谢谢。
0赞 chux - Reinstate Monica 5/30/2023
“例如,如果输出应该是 (-1, 0)” --> 的值是多少?a, b, c, d

答:

4赞 Yakov Galka 5/29/2023 #1

你得到的答案没有什么特别的错误。请记住,浮点计算本质上是近似的。事实上,和之间的距离小于 1ulp。大多数计算器为避免这种令人不快的输出所做的是用几个额外的数字进行计算,然后对结果进行四舍五入以适合显示。(1,0)(1, -2.0354088784794536E-16)

至于你的舍入代码,它舍入中间结果,而不是最终答案:

Round(num3, 0) * (b + new Complex (Round(tuple.Item1.Real, 0), Round(tuple.Item1.Imaginary, 0)) + num / tuple.Item1)

相反,您想要的是这样的内容:

int digits = 8;
Complex tmp = num3 * (b + tuple.Item1 + num / tuple.Item1);
tmp = new Complex(Round(tmp.Real, digits), Round(tmp.Imaginary, digits));

尽管最佳做法是让舍入在格式化例程中发生

评论

0赞 chux - Reinstate Monica 5/30/2023
“(1,0) 和 (1, -2.0354088784794536E-16) 之间的距离小于 1ulp”可能小于 1.0 的 1 ULP,但一般不小于 1.0 ULP。
0赞 Yakov Galka 5/30/2023
@chux-ReinstateMonica 术语“ULP”总是相对于某个特定值,所以我不确定你所说的“一般 1.0 ULP”是什么意思。我承认,在复数上使用 ULP 没有公认的定义。我在这里的目的是,您将使用相对于模量 |z|复数,这是实数的自然延伸。更好的表达方式可能是 |a-b|/|a|< ε