Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing a double against zero

Tags:

java

double

I'm new to Java and I've been trying to implement an algorithm for finding the roots of a cubical equation. The problem arises when I calculate the discriminant and try to check where it falls relative to zero.

If you run it and enter the numbers "1 -5 8 -4", the output is as follows:

1 -5 8 -4
p=-0.333333, q=0.074074
disc1=0.001372, disc2=-0.001372
discriminant=0.00000000000000001236
Discriminant is greater than zero.

I know the problem arises because the calculations with doubles are not precise. Normally the discriminant should be 0, but it ends up being something like 0.00000000000000001236.

My question is, what is the best way to avoid this? Should I check if the number falls between an epsilon neighborhood of zero? Or is there a better and more precise way?

Thank you in advance for your answers.

import java.util.Scanner;

class Cubical {
    public static void main(String[] args) {
        // Declare the variables.
        double a, b, c, d, p, q, gamma, discriminant;

        Scanner userInput = new Scanner(System.in);
        a = userInput.nextDouble();
        b = userInput.nextDouble();
        c = userInput.nextDouble();     
        d = userInput.nextDouble();

        // Calculate p and q.
        p = (3*a*c - b*b) / (3*a*a);
        q = (2*b*b*b) / (27*a*a*a) - (b*c) / (3*a*a) + d/a;

        // Calculate the discriminant.
        discriminant = (q/2)*(q/2) + (p/3)*(p/3)*(p/3);

        // Just to see the values.
        System.out.printf("p=%f, q=%f\ndisc1=%f, disc2=%f\ndiscriminant=%.20f\n", p, q, (q/2)*(q/2), (p/3)*(p/3)*(p/3), (q/2)*(q/2) + (p/3)*(p/3)*(p/3));

        if (discriminant > 0) {
            System.out.println("Discriminant is greater than zero.");
        }
        if (discriminant == 0) {
            System.out.println("Discriminant is equal to zero.");
        }
        if (discriminant < 0) {
            System.out.println("Discriminant is less than zero.");
        }
    }
}
like image 205
hattenn Avatar asked Nov 19 '11 15:11

hattenn


2 Answers

The simplest epsilon check is

if(Math.abs(value) < ERROR)

a more complex one is proportional to the value

if(Math.abs(value) < ERROR_FACTOR * Math.max(Math.abs(a), Math.abs(b)))

In your specific case you can:

if (discriminant > ERROR) {
    System.out.println("Discriminant is greater than zero.");
} else if (discriminant < -ERROR) {
    System.out.println("Discriminant is less than zero.");
} else {
    System.out.println("Discriminant is equal to zero.");
}
like image 169
Peter Lawrey Avatar answered Sep 28 '22 05:09

Peter Lawrey


Should I check if the number falls between an epsilon neighborhood of zero?

Exactly

like image 34
Jens Schauder Avatar answered Sep 28 '22 07:09

Jens Schauder