代码之家  ›  专栏  ›  技术社区  ›  BigBoronto

显示为难以置信的小小数的复数

  •  1
  • BigBoronto  · 技术社区  · 2 年前

    使用了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)
    

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

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

    1 回复  |  直到 2 年前
        1
  •  4
  •   Yakov Galka    2 年前

    你得到的答案没有什么特别的错误。记住这一点 floating point calculations are inherently approximate 。事实上 (1,0) (1, -2.0354088784794536E-16) 小于1ulp。大多数计算器所做的是用几个额外的数字进行计算,并将结果四舍五入以适应显示器,从而避免这种令人不快的输出。

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

    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));
    

    尽管最好的做法是让 rounding happen in the formatting routine

    推荐文章