1

Recently I was working on a discord bot to compute the roots of a cubic equation.

I have already made another program beforehand in C# that basically does the same thing, and is proven to work correctly, so I straight up copied the codes into the one which I am working with now.

(Suppose that I am calculating the roots of 7x3 + 2x2 + 12x + 9 = 0)
The code below is from the program which was created beforehand:
(Once again, the program and the results are proven to be correct, results are listed at the bottom of the code)*

// parts 1-5
double p1 = -(b / (3 * a));
double p2 = (b * c / (6 * Math.Pow(a, 2))) - (Math.Pow(b, 3) / (27 * Math.Pow(a, 3))) - (d / (2 * a));
double p3 = (c / (3 * a)) - (Math.Pow(b, 2) / (9 * Math.Pow(a, 2)));
Complex p4 = new Complex(-1.0 / 2, Math.Sqrt(3) / 2);
Complex p5 = new Complex(-1.0 / 2, -(Math.Sqrt(3) / 2));

// solve for roots
Complex root1 = p1 + Math.Cbrt(p2 + Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3))) +
                 Math.Cbrt(p2 - Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3)));
Complex root2 = p1 + (p4 * Math.Cbrt(p2 + Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3)))) +
                 (p5 * Math.Cbrt(p2 - Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3))));
Complex root3 = p1 + (p5 * Math.Cbrt(p2 + Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3)))) +
                 (p4 * Math.Cbrt(p2 - Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3))));
/* 
results :
root1 = (-0.6566823203779361, 0)
root2 = (0.18548401733182518, 1.3868992549529795)
root3 = (0.18548401733182518, -1.3868992549529795)
*/

I proceed to copy the whole thing into the new program I am working on. Then I realized in my new program the Math.Cbrt function doesn't exist (I don't know why). Therefore I made a custom program to tackle this problem, here is the code in my new program :
(This is the problematic program, the results are different from the first one's.)

// parts 1-5
double p1 = -(b / (3 * a));
double p2 = (b * c / (6 * Math.Pow(a, 2))) - (Math.Pow(b, 3) / (27 * Math.Pow(a, 3))) - (d / (2 * a));
double p3 = (c / (3 * a)) - (Math.Pow(b, 2) / (9 * Math.Pow(a, 2)));
Complex p4 = new Complex(-1.0 / 2, Math.Sqrt(3.0) / 2);
Complex p5 = new Complex(-1.0 / 2, -(Math.Sqrt(3.0) / 2));

// solve for roots
Complex root1 = p1 + Cbrt(p2 + Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3))) +
     Cbrt(p2 - Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3)));
Complex root2 = p1 + (p4 * Cbrt(p2 + Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3)))) +
                 (p5 * Cbrt(p2 - Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3))));
Complex root3 = p1 + (p5 * Cbrt(p2 + Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3)))) +
                 (p4 * Cbrt(p2 - Math.Sqrt(Math.Pow(p2, 2) + Math.Pow(p3, 3))));

public static Complex Cbrt(Complex value)
{
    Complex result = Complex.Pow(value, 1D / 3);
    return result;
}
/* 
results :
root1 = (0.965490835755936, 0.936562108366076)
root2 = (0.185484017331825, -0.486224961779172)
root3 = (-1.43668913880205, -0.450337146586904)
*/

I have tried to extract different sections of the codes and run it separately but I still wasn't able to find what the cause is. If the codes are the same, why do they yield different results? Or is the Cbrt method I have created the real problem behind this?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Tsain
  • 67
  • 6
  • 1
    It looks like [Math.Crbt](https://learn.microsoft.com/en-us/dotnet/api/system.math.cbrt?view=netcore-3.0) was added in .net core 3. I would recommend using the latest version of .net, i.e. Net 6 if you have that choice. – JonasH Mar 18 '22 at 10:43
  • To check if your Crbt method is correct you should write a unit test that compare the result for some values with known correct values. – JonasH Mar 18 '22 at 10:44
  • ...maybe have a look at a similar question https://stackoverflow.com/q/71508008/803359 – mikuszefski Mar 18 '22 at 10:44
  • @JonasH but how would I be able to change its version? Is it necessary for me to create a new program and duplicate the whole thing or set everything up again? – Tsain Mar 18 '22 at 10:47
  • 2
    additionally I think that the main point of `cbrt()` is that `cbrt( -1 ) = -1`. Not sure if your implementation does this. – mikuszefski Mar 18 '22 at 10:48
  • @mikuszefski So that basically implies that my own Cbrt() function operates differently from the Math.Cbrt() function? – Tsain Mar 18 '22 at 10:50
  • ...probably....did not check...point would be that the cbrt of a negative real number is supposed to be a negative real number. Guess you can check this easily. – mikuszefski Mar 18 '22 at 10:52
  • 1
    @mikuszefski you were right, the problem was because of the cube root function functions wrongly when calculating negative numbers. Thanks! – Tsain Mar 18 '22 at 10:58
  • 1
    Switching frameworks depend largely on how complex the projects are. For a simple program it might be easiest creating a new .Net 6 project and moving the code files over, since .net core+ uses a different project format. – JonasH Mar 18 '22 at 11:03
  • 1
    You can solve the cubic without resorting to complex numbers. In the single-real-root case, you take cubic roots of reals; in the three-real-roots case (casus irreductibilis), you resort to trigonometry. After you have found one root, you can reduce to a quadratic equation by division. –  Mar 18 '22 at 14:18

1 Answers1

0

Refering @mikuszefski 's comment,

The real cause behind this is that the Cbrt() function I have created calculates negative numbers wrongly.

For example, Cbrt(-1) should yield the result -1.
However, the answer I have gotten instead is (NaN, 0).
I have found the solution in another thread.

Tsain
  • 67
  • 6