194 votes

Résultats inattendus lorsque vous travaillez avec des très grands entiers sur les langages interprétés

J'essaie d'obtenir la somme des 1 + 2 + ... + 1000000000, mais je suis arriver de drôles de résultats en PHP et Node.js.

PHP

$sum = 0;
for($i = 0; $i <= 1000000000 ; $i++) {
    $sum += $i;
}
printf("%s", number_format($sum, 0, "", ""));   // 500000000067108992

Node.js

var sum = 0;
for (i = 0; i <= 1000000000; i++) {
    sum += i ;
}
console.log(sum); // 500000000067109000

La bonne réponse peut être calculée à l'aide de

1 + 2 + ... + n = n(n+1)/2

Bonne réponse = 500000000500000000, j'ai donc décidé d'essayer une autre langue.

ALLER

var sum , i int64
for i = 0 ; i <= 1000000000; i++ {
    sum += i
}
fmt.Println(sum) // 500000000500000000

Mais il fonctionne très bien! Alors quel est le problème avec mon PHP et Node.js code?

Peut-être est ce un problème de langages interprétés, et c'est pourquoi il travaille dans un langage compilé comme Aller? Si oui, aurait-il d'autres langages tels que Python et Perl ont le même problème?

155voto

dawg Points 26051

Python fonctionne:

>>> sum(x for x in xrange(1000000000 + 1))
500000000500000000

Ou:

>>> sum(xrange(1000000000+1))
500000000500000000

Python int auto fait la promotion d'un Python long qui prend en charge une précision arbitraire. Il va produire la réponse correcte sur 32 ou 64 bits plates-formes.

Ceci peut être vu par le relèvement de 2 à une puissance bien plus grande que le peu de largeur de la plate-forme:

>>> 2**99
633825300114114700748351602688L

Vous pouvez démontrer (avec Python) que les valeurs erronées que vous obtenez en PHP, c'est parce que PHP est la promotion d'un flotteur lorsque les valeurs sont supérieures à 2**32-1:

>>> int(sum(float(x) for x in xrange(1000000000+1)))
500000000067108992

100voto

zzzz Points 23017

Votre code Go utilise l’arithmétique sur les entiers possédant suffisamment de bits pour donner une réponse exacte. Jamais touché PHP ou Node.js, mais d’après les résultats, je soupçonne que le calcul se fait à l’aide de nombres à virgule flottante et devraient par conséquent ne pas pour être exact pour les numéros de cette ampleur.

46voto

user568109 Points 21253

La raison en est que la valeur de votre variable de type entier sum supérieur à la valeur maximale. Et l' sum vous obtenez est le résultat de flotteur point de l'arithmétique qui consiste à arrondir. Depuis d'autres réponses de ne pas mentionner les limites exactes, j'ai décidé de le poster.

Le max valeur entière pour PHP:

  • Version 32 bits est de 2 147 483 647
  • Version 64-bit est 9223372036854775807

Donc, cela signifie soit que vous êtes en utilisant 32 bits PROCESSEUR ou OS 32 bits ou 32 bits version compilée de PHP. Il peut être trouvé à l'aide de PHP_INT_MAX. L' sum serait calculé correctement si vous le faites sur un ordinateur 64 bits.

Le max valeur entière en JavaScript est 9007199254740992. La plus exacte de la valeur intégrale, vous pouvez travailler avec est 253 (prises à partir de cette question). L' sum dépasse cette limite.

Si la valeur de l'entier de ne pas dépasser ces limites, alors vous êtes bon. Sinon, vous aurez à chercher une précision arbitraire entier bibliothèques.

27voto

CyberSkull Points 415

Voici la réponse en C, par souci d'exhaustivité:

#include <stdio.h>

int main(void)
{
    unsigned long long sum = 0, i;

    for (i = 0; i <= 1000000000; i++)    //one billion
        sum += i;

    printf("%llu\n", sum);  //500000000500000000

    return 0;
}

La clé dans ce cas est l'utilisation du C99 long long type de données. Il offre la plus primitive de stockage de C peut gérer et il fonctionne vraiment, vraiment rapide. L' long long type va également travailler sur la plupart des quelque 32 bits ou 64 bits de la machine.

Il existe toutefois une exception: les compilateurs fourni par Microsoft explicitement ne prennent pas en charge le jeune de 14 ans en standard C99, afin d'obtenir une exécution dans Visual Studio est un crapshot.

21voto

Ted Hopp Points 122617

Ma conjecture est que lorsque la somme dépasse la capacité d’un natif `` (2,<sup>32</sup>-1 = 2 147 483 647), Node.js et PHP interrupteur en position flottante point représentation et vous commencez à recevoir des erreurs d’arrondi. Une langue comme le Go essaiera probablement s’en tenir à une forme de nombre entier (par exemple, les entiers 64 bits) aussi longtemps que possible (si, en effet, il n’a pas commencé avec ça). Car la réponse s’inscrit dans un entier 64 bits, le calcul est exact.

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