2010-02-01 3 views
3

Je fais un programme Java pour calculer la règle de Simpson pour Intégrales. Voici le code que j'ai. Notez la deuxième colonne de nombres dans les valeurs de sortie de count == 4,9,10,11. Ce ne sont pas des chiffres dont j'ai besoin, ils ne suivent pas le modèle. J'ai besoin de ces chiffres pour être précis. Que se passe-t-il et comment puis-je le réparer?java pour boucle problème

public static void main(String[] args) 
{ 
    double totalS = 0.0; 
    int count = 0; 

    for(double i=0; i< 4; i += 0.4) 
    { 
      count++; 
      totalS += Sfunction(i, count); 
      System.out.println(count + " " + i + " " + totalS); 
    } 
} 

public static double Sfunction(double f1, int count) 
{ 
    double value; 

    if (f1 == 0.0 || f1 == 4.0) 
     value = Math.cos(Math.sqrt(f1)); 
    else if ((count % 2) == 1) 
     value = 2 * Math.cos(Math.sqrt(f1)); 
    else 
     value = 4 * Math.cos(Math.sqrt(f1)); 

    return value; 
} 

je reçois la sortie:

1 0.0 1.0 
2 0.4 4.226313639540303 
3 0.8 5.478244888601832 
4 1.2000000000000002 7.30884788480188 
5 1.6 7.911122809972827 
6 2.0 8.534897589034324 
7 2.4 8.578100205110182 
8 2.8 8.168723348285942 
9 3.1999999999999997 7.736055200662704 
10 3.5999999999999996 6.452869366954546 
11 3.9999999999999996 5.620575693860261 
+1

De quels numéros avez-vous besoin? Comment la sortie est-elle incorrecte? Vous plaignez-vous que les nombres à virgule flottante ne sont pas précis? Si oui, lisez attentivement http://en.wikipedia.org/wiki/Floating_point. – Bear

+0

La question que je suis est dans la deuxième colonne de la sortie, pourquoi est seulement quelques chiffres dans la précision correcte des chiffres et certains ne le sont pas? – TrickyM66

Répondre

7

Chaque fois que vous allez autour de votre boucle, vous compoundage l'erreur dans l'addition de 0,4 à inexacte i.

Au lieu de cela, utilisez une valeur intégrale du compteur de boucle, et une échelle pour obtenir une meilleure approximation des valeurs:

for (int count = 0; count < 10; ++count) { 
     final double i = 0.4 * count; 
     System.out.println ((count + 1) + " " + i); 
    } 

Cela ne supprimera pas l'erreur de virgule flottante, mais cela signifie qu'il n'est pas augmentant à chaque itération. Pour supprimer l'erreur de la sortie, formatez la sortie sur un nombre raisonnable de décimales:

for (int count = 0; count < 10; ++count) { 
     final double i = 0.4 * count; 
     System.out.printf ("%2d %.1f\n", (count + 1), i); 
    } 
+0

J'ai pris votre idée et utilisé DecimalFormat pour corriger la précision. Merci – TrickyM66

6

Ceci est un problème du point Floating classique. Si vous avez besoin de précision dans vos décimales, vous devriez utiliser BigDecimal

+3

Les doublons sont susceptibles d'être suffisants pour l'intégration numérique. – duffymo

+0

Cela ne résoudra pas complètement le problème de toute façon. Voir http://stackoverflow.com/questions/2173512/java-bigdecimal-trigonometric-methods – finnw

1

Ce que vous voyez est un résultat de floating point precision error, les chiffres ne sont pas stockés comme vous le pensez probablement. Vous pouvez arrondir la réponse à 1 décimale pour se débarrasser de l'erreur ... mais c'est juste une conséquence de la façon dont les doubles sont stockés dans Java.

+1

Ceci est d'ailleurs pas explicitement lié à Java. Juste pour les points flottants dans l'informatique générale et c'est * quel * soit le langage de programmation que vous utilisez. – BalusC

+0

@BalusC - C'est vrai, mais le '.ToString()' dans certaines langues en tient compte, donc ce que vous voyez dans une console peut différer. –

1

Votre problème est que vous utilisez l'arithmétique en virgule flottante qui ne peut valeurs approximatives, mais en supposant que vous avez une précision infinie. Vous ne devriez pas faire des tests d'égalité comme celui-ci avec des nombres à virgule flottante:

if (f1 == 0.0 || f1 == 4.0) 

Tout test d'égalité avec un nombre à virgule flottante est une odeur de code. Avec un flotteur, vous devriez toujours vérifier s'il se trouve dans une certaine plage, par exemple dans la plage de 3,9999 à 4,0001.

Dans cet exemple précis cependant, vous aussi avez un autre haut la main paramètre appelé count qui est un entier. Vous pouvez faire des tests d'égalité avec cela. Peut-être que vous pouvez tester cela à la place.

1

essayer de les imprimer avec un seul chiffre décimal:

System.out.printf("%.1f", Math.E); // prints 2.7 
System.out.printf("%.2f", Math.E); // prints 2.72 
System.out.printf("%.3f", Math.E); // prints 2.718 

ou même essayer de spécifier le mot-clé strictfp pour votre numéro méthodes crissement

1

À partir de votre condition de la boucle, il semble que vous ne Je ne veux pas que la ligne 11 soit traitée. Je vous recommande d'utiliser un index de boucle entier et de l'utiliser pour calculer les valeurs que vous passez à Sfunction. Ce qui suit devrait être l'équivalent de ce que vous avez maintenant (à l'exception de la ligne 11).

double totalS = 0.0; 

for(int i = 1; i <= 10; i++) 
{ 
    double f1 = 0.4 * (i - 1); 
    totalS += Sfunction(f1, i); 
    System.out.println(i + " " + f1 + " " + totalS); 
} 

Votre problème avec une précision d'impression peut être résolu avec DecimalFormat, comme l'a suggéré dans d'autres réponses.

+1

Mais il est plus simple d'utiliser 'Formatter' (via' System.out.printf() ') que' DecimalFormat' – finnw

+0

@finnw: Bien sûr, vous avez raison. J'oublie presque toujours qu'ils ont ajouté printf à Java à moins qu'une certaine forme d'intellisense me rappelle. –