tags:

views:

349

answers:

5

I am looking to implement the simple equation:

i,j = -Q ± √(Q2-4PR) / 2P

To do so I have the following code (note: P = 10. Q = 7. R = 10):

    //Q*Q – 4PR = -351 mod 11 = -10 mod 11 = 1, √1 = 1
    double test = Math.sqrt(modulo(((Q*Q) - ((4*P)*R))));

    // Works, but why *-10 needed?
    i = (int)(((-Q+test)/(P*2))*-10);    // i = 3
    j = (int)(((-Q-test)/(P*2))*-10);    // j = 4

To put it simply, test takes the first part of the equation and mods it to a non-zero integer in-between 0 and 11, then i and j are written. i and j return the right number, but for some reason *-10 is needed to get them right (a number I guessed to get the correct values).

If possible, I'd like to find a better way of performing the above equation because my way of doing it seems wrong and just works. I'd like to do it as the equation suggests, rather than hack it to work.

+6  A: 

The quadratic equation is more usually expressed in terms of a, b and c. To satisfy ax2+bx+c = 0, you get (-b +/- sqrt(b^2-4ac)) / 2a as answers.

I think your basic problem is that you're using modulo for some reason instead of taking the square root. The factor of -10 is just a fudge factor which happens to work for your test case.

You should have something like this:

public static void findRoots(double a, double b, double c)
{
    if (b * b < 4 * a * c)
    {
        throw new IllegalArgumentException("Equation has no roots");
    }

    double tmp = Math.sqrt(b * b - 4 * a * c);
    double firstRoot = (-b + tmp) / (2 * a);
    double secondRoot = (-b - tmp) / (2 * a);
    System.out.println("Roots: " + firstRoot + ", " + secondRoot);
}

EDIT: Your modulo method is currently going to recurse pretty chronically. Try this instead:

public static int modulo(int x)
{
    return ((x % 11) + 11) % 11;
}

Basically the result of the first % 11 will be in the range [-10, 10] - so after adding another 11 and taking % 11 again, it'll be correct. No need to recurse.

At that point there's not much reason to have it as a separate method, so you can use:

public static void findRoots(double a, double b, double c)
{       
    int squareMod11 = (((b * b - 4 * a * c) % 11) + 11) % 11;
    double tmp = Math.sqrt(squareMod11);
    double firstRoot = (-b + tmp) / (2 * a);
    double secondRoot = (-b - tmp) / (2 * a);
    System.out.println("Roots: " + firstRoot + ", " + secondRoot);
}
Jon Skeet
The reason I'm using those variable names is because I'm already using a, b, and c elsewhere later on in my code to represent other codewords. The reason I'm using modulo is written above; in essence I'm trying to mimic the new equation I've written at the bottom of my post. I've tried your code and it throws the IllegalArgumentException each time.
AlexT
IF it's trhowhing an IllegalArgumentException you're equation has a non-real result. If you want to use complex numbers, you'll have to "manually" implement and handle them in Java.
svens
I've changed each number to a double and removed all the typecasting. Now, i = -0.3 and j = -0.4, meaning that the results would be right if I were to multiply by -10 again. I am trying to mimic the i and j equations in my post but am struggling with that part.
AlexT
@AlexT: If P=10, Q=7 and R=10 then you're trying to take the square root of -51, which won't work without complex numbers. You still haven't really explained why you've decided to use modulo when your original equation doesn't contain it. Are you trying to work with the original equation or not?
Jon Skeet
If you are already using variables a,b,c then why not extract the Quadratic Equation into a separate function? You can then give the variables in the new function any names you like. Act upon the principle of least surprise. People will expect to see variables a,b,c when they see a quadratic equation. You could even call the new method solveQuadraticEquation().
Fortyrunner
+1  A: 

You need to take the square root. Note that Q^2-4PR yields a negative number, and consequently you're going to have to handle complex numbers (or restrict input to avoid this scenario). Apache Math may help you here.

Brian Agnew
+1  A: 

use Math.sqrt for the square root. Why do you cast i and j to ints? It is equation giving you roots of square function, so i and j can be any complex numbers. You shall limit the discriminant to positive-only values for real (double) roots, otherwise use complex numbers.


double test = Q*Q - 4*P*R;
if(Q < 0) throw new Exception("negative discriminant!");
else {
    test = Math.sqrt(test);
    double i = (-Q + test) / 2*P;
    double i = (-Q - test) / 2*P;
}
raceCh-
squrt, squrt, squrt
BalusC
fixed it, thx! :)
raceCh-
A: 

Why are you doing modulo and not square root? Your code seems to be the way to get the roots of a quadratic equation ((a±sqrt(b^2-4ac))/2a), so the code should be:

double delta = Q*Q-4*P*R);
if(delta < 0.0) {
  throw new Exception("no roots");
}
double d = Math.power(delta,0.5);
double r1 = (Q + d)/(2*P)
double r2 = (Q - d)/(2*P)
David Rabinowitz
A: 

As pointed out by others, your use of mod isn't even wrong. Why are you making up mathematics like this?

It's well known that the naive solution to the quadratic equation can have problems if the value of b is very nearly equal to the discriminant.

A better way to do it is suggested in section 5.6 of "Numerical Recipes in C++": if we define

alt text

Then the two roots are:

alt text

and

alt text

Your code also needs to account for pathological cases (e.g., a = 0).

Let's substitute your values into these formulas and see what we get. If a = 10, b = 7, and c = 10, then :

alt text

Then the two roots are:

alt text

and

alt text

I think I have the signs right.

If your calculation is giving you trouble, it's likely due to the fact that you have complex roots that your method can't take into account properly. You'll need a complex number class.

duffymo
Hmm, that looks OK at first glance, but I've had trouble with Numerical Recipes before, and apparently I'm not the only one: http://amath.colorado.edu/computing/Fortran/numrec.html
Ken
Yes, Numerical Recipes has that reputation, but this formula isn't part of it. The complaints have to do with the implementations, not the mathematics or the text.
duffymo
It should also be noted that the Shampine review of the ODE chapter commented on the first edition; the second edition incorporated many of his suggestions; see http://www.nr.com/bug-rebutt.html
duffymo