40 votes

Java For-loop change le résultat numérique lors du changement de type de variable de boucle

J'ai écrit un programme pour calculer le nombre PI avec Leibniz formule:

[Leibniz formula]

J'ai écrit une boucle avec le type d'initialisation est "int" , la boucle fonctionne bien mais quand j'ai changé l'initialisation de type "long", le résultat est changé. Cela se produit uniquement lorsque la boucle de temps de plus d'un milliard de dollars. Cela rend le "int" en boucle calcule PI plus précis que "long" en boucle. Je ne sais pas pourquoi cela se produit. Merci de m'aider à comprendre ce problème. Merci! et voici mon code.

public static void main(String[] args) {
    double result1 = 0;
    double result2 = 0;
    double sign = 1;

    for (int i = 0; i <= 1607702095; i++) {
        result1 += sign/(2 * i + 1);
        sign *= -1;
    }
    sign = 1;

    for (long j = 0; j <= 1607702095; j++) {
        result2 += sign/(2 * j + 1);
        sign *= -1;
    }

    System.out.println("result1  " + result1 * 4);
    System.out.println("result2  " + result2 * 4);
    System.out.println("pi       " + Math.PI);
}

Et le résultat est:

result1  3.141592653576877
result2  3.1415926529660116
pi       3.141592653589793

34voto

Eran Points 35360

En fait, votre première boucle aurait int de dépassement dans le calcul de l' (2 * i + 1) lorsque i est assez grand, donc il ne faut pas se fier à la sortie de il.

La deuxième boucle, d'autre part, produit une plus correct de sortie, depuis (2 * j + 1) ne déborde pas, puisqu'il effectue long de multiplication.

Cela rend le "int" en boucle calcule PI plus précis que "long"en boucle

C'est probablement juste une coïncidence, étant donné que les calculs dans l' int boucle de débordement.

12voto

Parce que vous obtenez un débordement à la ligne

 result1 += sign/(2 * i + 1);
 

Où la valeur de 2*i croise la valeur entière maximale

La plage int est -2,147,483,648 to 2,147,483,647 mais lorsque vous effectuez une opération 2*i , elle dépasse cette plage.

Mieux vaut rester avec long et cela vous donne une sortie correcte.

11voto

2 * i lorsque i est proche de la fin de votre boucle de dépassement de la max int valeur qui est 2147483647

À l'aide d'un long que l'opération ne déborde pas.

La procédure correcte est d'utiliser un type long. Probablement parce que les valeurs sont ajoutés et supprimés autour de la bonne PI pour un comportement étrange les débordements momentaneally calculer une valeur plus proche de la droite PI.

Je suppose que le changement de la limite supérieure de la boucle de quelques valeurs vont changer le résultat final à une valeur qui est plus loin du droit de la PI.

10voto

nicomp Points 1443

Vous avez un débordement d'entier.

La capacité maximale d'un entier signé est de (2 ^ 31) -1 ou 2 147 483 647.

(1 607 702 095 * 2) correspond à 3215404190, ce qui est supérieur à 2 147 483 647.

Lorsque vous modifiez i sur une position longue, vous augmentez la capacité de i à (2 ^ 63) -1.

7voto

JordiVilaplana Points 343

Vous remarquerez que tout le monde pointe le débordement d’entier, mais vous voudrez peut-être une solution. (Si vous en avez déjà un, veuillez ignorer ce qui suit :))

Ayant le débordement dans la partie (2 * i + 1) du code, vous devez utiliser au maximum i dans la boucle for pour atteindre (Integer.MAX_VALUE / 2 - 1) , ce qui donne:

 for (int i = 0; i <= (Integer.MAX_VALUE / 2 - 1); i++) {
    result1 += sign/(2 * i + 1);
    sign *= -1;
}
 

Vous pouvez également le faire à long terme avec (Long.MAX_VALUE / 2 - 1) mais cela fonctionnera très longtemps.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X