0

I want to create a Java method which returns the lowest root of a quadratic equation in the interval (0, 1). If there are no solutions in the interval, return 1. I need some help making this an efficient algorithm.

This is my current method:

public static float getLowestRoot(float A, float B, float C) {
    float D = B*B - 4*A*C;
    if(D < 0) return 1;

    float sD = (float) Math.sqrt(D);

    float x1 = (-B + sD) / (2*A);
    float x2 = (-B - sD) / (2*A);

    if(x2 < x1) {
        float tmp = x2;
        x2 = x1;
        x1 = tmp;
    }

    if(x1 > 0 && x1 < 1) return x1;
    if(x2 > 0 && x2 < 1) return x2;

    return 1;
}

This method does the job but I was wondering if there is a way to compress the algorithm, because right now it feels bloated.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Wilco
  • 928
  • 3
  • 9
  • 20
  • What if the solution is 1? – arynaq Oct 15 '13 at 13:10
  • I suggest switching the `float` with `double`. You will get more precise results. – Konstantin Yovkov Oct 15 '13 at 13:12
  • I think that there's nothing fundamentally wrong with your code (except that I would *definitely* not use 1.0 to indicate "no solution" since it's also a valid solution). – NPE Oct 15 '13 at 13:14
  • @arynaq: then the return value should be 1. – Wilco Oct 15 '13 at 13:15
  • @kocko: thanks for the suggestion but I don't need precision, floats are fine. – Wilco Oct 15 '13 at 13:15
  • "If it's not broke don't fix it." Why do you think it's 'bloated'? Looks short and clean to me. – Troubleshoot Oct 15 '13 at 13:16
  • @NPE: In this application, I want 1.0 to be the return value if there are no solutions. But let's say I don't, what would be the return value in case of no solutions? It has to be a float right? – Wilco Oct 15 '13 at 13:17
  • @Wilco: NaN sounds like a good candidate. http://en.wikipedia.org/wiki/NaN – NPE Oct 15 '13 at 13:18
  • @Troubleshoot: In this case I am searching for a method with maximum performance. The stated problem is really simple, and it feels like I am missing something which could easily reduce the algorithm into less lines of code. – Wilco Oct 15 '13 at 13:19
  • If you know where the max / min is, then you may check the values of y(0) and y(1) first, since you might be able to skip rooting then, if all points have the same sign. – jgroenen Oct 15 '13 at 14:48

1 Answers1

0

1) note that "less lines of code" isn't the same as "better performance".

2) you can consider Math.abs(sD) < Epsilon - if yes, then you don't have to calculate both roots. I'm guessing that this can improve speed in such cases.

3) I think you can improve checking which root is smaller:

x1 <= x2 <===>  -B+sD/(2A) <= -B-sD/(2A) <==(adding sD/(2A) to both sides)==> 
         <===> -B+2sD/(2A) <= -B/(2A)    <==(adding B/(2A) to both sides)==>
         <===>    2sD/(2A) <= 0
         <===>           A <= 0 (because sD >= 0)

So you can avoid swapping the roots:

int signA = Math.signum(A);
float x1 = (-B + -signA * sD) / (2*A);
float x2 = (-B + signA * sD) / (2*A);

// always x1 <= x2

Again, I'm guessing that this improves performance, but I didn't measure it.

So, the final answer would look something like this:

public static float getLowestRoot(float A, float B, float C) {
    float D = B*B - 4*A*C;

    if (D < 0) return 1;

    if (Math.abs(D) < 0.0001)  // not sure how many 0s for float
    {
        float x = -B / (2*A);

        if (x > 0 && x < 1) return x;

        return 1;
    }

    float sD = (float) Math.sqrt(D);

    int signA = Math.signum(A);
    float x1 = (-B + -signA * sD) / (2*A);
    float x2 = (-B + signA * sD) / (2*A);

    if (x1 > 0 && x1 < 1) return x1;
    if (x2 > 0 && x2 < 1) return x2;

    return 1;
}
BartoszKP
  • 34,786
  • 15
  • 102
  • 130