La comparaison d'un double contre zéro
Je suis débutant en Java et j'ai essayé de mettre en œuvre un algorithme pour trouver les racines d'une équation cubique. Le problème se pose lorsque je calcule le discriminant et essayez de vérifier, d'où il tombe par rapport à zéro.
Si vous l'exécuter et entrez les numéros "1 -5 8 -4", le résultat est comme suit:
1 -5 8 -4
p=-0.333333, q=0.074074
disc1=0.001372, disc2=-0.001372
discriminant=0.00000000000000001236
Discriminant is greater than zero.
Je sais que le problème se pose parce que les calculs avec des doubles ne sont pas précis. Normalement le discriminant doit être de 0, mais il finit par être quelque chose comme 0.00000000000000001236.
Ma question est, quelle est la meilleure façon d'éviter cela? Dois-je vérifier si le nombre se situe entre un epsilon voisinage de zéro? Ou est-il une meilleure et plus précise?
Je vous remercie d'avance pour vos réponses.
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.");
}
}
}
Vous devez vous connecter pour publier un commentaire.
Le plus simple epsilon case est
plus complexe est proportionnelle à la valeur
Dans votre cas particulier, vous pouvez:
Exactement
Voici la solution qui est précis lors de la saisie de valeurs sont des entiers, mais il n'est probablement pas le plus pratique.
Il sera probablement aussi bon sur des valeurs d'entrée qui a une durée de représentation binaire (par exemple. 0.125 fait, mais de 0,1 ne marche pas).
L'astuce: Supprimer toutes les divisions de la les résultats intermédiaires et seulement diviser une fois à la fin. Ceci est fait en gardant la trace de tous les (partielle) les numérateurs et les dénominateurs. Si le discriminant doit être égale à 0 alors il est numérateur sera être 0. Aucune erreur d'arrondi, ici aussi longtemps que les valeurs intermédiaires des ajouts sont à l'intérieur d'une magnitude de ~2^45 les uns des autres (ce qui est généralement le cas).
(seulement vérifié sur la condition des valeurs d'entrée, alors, dites-moi si quelque chose ne va pas)
peut-être
BigDecimal
vaut un coup d'oeil...http://download.oracle.com/javase/1.4.2/docs/api/java/math/BigDecimal.html
vous pouvez secify le mode tour dans la division de l'opération