1

Was using a method from the MathNet Library and tried applying its Cubic root finding function, but it outputs incredibly long decimals, and rounding doesn't seem to affect them.

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

The code above works fine, but really not sure how to shorten the decimals in the results. For example if the output should be (-1, 0) in theory (and it does display so on most calculators), it instead displays (-1, -2.0354088784794536E-16), which is close to 0, and should be displayed as 0.

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

The rounding code in question since you can't directly round complex numbers.

Solved in comment: Forgot about floating point inaccuracy.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
BigBoronto
  • 33
  • 6

1 Answers1

4

There's nothing particularly wrong with the answer you get. Remember that floating point calculations are inherently approximate. Indeed, the distance between (1,0) and (1, -2.0354088784794536E-16) is less than 1ulp. What most calculators do to avoid such unpleasant outputs is to calculate with a couple extra digits and round the result to fit the display.

As for your rounding code, it rounds intermediary results rather than the final answer:

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

What you want instead is something like this:

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

Though the best practice would be to let the rounding happen in the formatting routine.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • "distance between (1,0) and (1, -2.0354088784794536E-16) is less than 1ulp" may be less than 1 ULP of 1.0, but it is not less than 1.0 ULP in general. – chux - Reinstate Monica May 30 '23 at 01:08
  • @chux-ReinstateMonica The term "ULP" is always relative to some specific value, so I'm not sure what you mean by "1.0 ULP in general". I acknowledge that using ULP on complex numbers does not have a commonly agreed definition. My intent here is that you'd use ULP relative to the modulus |z| of the complex number, which is a natural extension from reals. A better way to phrase it might be that |a-b|/|a| < ε – Yakov Galka May 30 '23 at 02:15