Pourquoi Java pense-t-il que le produit de tous les nombres de 10 à 99 est 0?


131

Le bloc de codes suivant donne la sortie à 0.

public class HelloWorld{

    public static void main(String []args){
        int product = 1;
        for (int i = 10; i <= 99; i++) {
            product *= i;
        }
        System.out.println(product);
    }
}

Quelqu'un peut-il expliquer pourquoi cela se produit?


106
Vous avez très probablement un débordement d'entier.
TheLostMind

68
Si vous tenez compte des facteurs premiers du produit, vous vous présenterez 2environ 90 fois. Cela signifie que vous aurez besoin d'une variable d'au moins 90 bits pour obtenir une sortie non nulle. 32 et 64 sont tous deux inférieurs à 90. Afin de calculer des entiers plus grands que les mots natifs, vous devez utiliser la grande classe d'entiers disponible dans la langue choisie.
kasperd

62
Techniquement, c'est le produit des nombres de 10 à 98.
AShelly

45
Quoi? Pourquoi cette question a-t-elle été fermée comme un double d'une question qui est fermée comme un double de cette question ?
Salman A

82
J'ai 99 problèmes et 2147483648 n'est pas le 1.
glenatron

Réponses:


425

Voici ce que fait le programme à chaque étape:

          1 * 10 =          10
         10 * 11 =         110
        110 * 12 =        1320
       1320 * 13 =       17160
      17160 * 14 =      240240
     240240 * 15 =     3603600
    3603600 * 16 =    57657600
   57657600 * 17 =   980179200
  980179200 * 18 =   463356416
  463356416 * 19 =   213837312
  213837312 * 20 =   -18221056
  -18221056 * 21 =  -382642176
 -382642176 * 22 =   171806720
  171806720 * 23 =  -343412736
 -343412736 * 24 =   348028928
  348028928 * 25 =   110788608
  110788608 * 26 = -1414463488
-1414463488 * 27 =   464191488
  464191488 * 28 =   112459776
  112459776 * 29 = -1033633792
-1033633792 * 30 =  -944242688
 -944242688 * 31 =   793247744
  793247744 * 32 =  -385875968
 -385875968 * 33 =   150994944
  150994944 * 34 =   838860800
  838860800 * 35 =  -704643072
 -704643072 * 36 =   402653184
  402653184 * 37 =  2013265920
 2013265920 * 38 =  -805306368
 -805306368 * 39 = -1342177280
-1342177280 * 40 = -2147483648
-2147483648 * 41 = -2147483648
-2147483648 * 42 =           0
          0 * 43 =           0
          0 * 44 =           0
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
          0 * 97 =           0
          0 * 98 =           0

Notez que sur certaines étapes, la multiplication entraîne un nombre plus petit (980179200 * 18 = 463356416) ou un signe incorrect (213837312 * 20 = -18221056), indiquant qu'il y a eu un dépassement d'entier. Mais d'où vient le zéro? Continuer à lire.

En gardant à l'esprit que intle type de données est un entier 32 bits signé , complément à deux , voici une explication de chaque étape:

Operation         Result(1)     Binary Representation(2)                                           Result(3)
----------------  ------------  -----------------------------------------------------------------  ------------
          1 * 10            10                                                               1010            10
         10 * 11           110                                                            1101110           110
        110 * 12          1320                                                        10100101000          1320
       1320 * 13         17160                                                    100001100001000         17160
      17160 * 14        240240                                                 111010101001110000        240240
     240240 * 15       3603600                                             1101101111110010010000       3603600
    3603600 * 16      57657600                                         11011011111100100100000000      57657600
   57657600 * 17     980179200                                     111010011011000101100100000000     980179200
  980179200 * 18   17643225600                               100 00011011100111100100001000000000     463356416
  463356416 * 19    8803771904                                10 00001100101111101110011000000000     213837312
  213837312 * 20    4276746240                                   11111110111010011111100000000000     -18221056
  -18221056 * 21    -382642176  11111111111111111111111111111111 11101001001100010101100000000000    -382642176
 -382642176 * 22   -8418127872  11111111111111111111111111111110 00001010001111011001000000000000     171806720
  171806720 * 23    3951554560                                   11101011100001111111000000000000    -343412736
 -343412736 * 24   -8241905664  11111111111111111111111111111110 00010100101111101000000000000000     348028928
  348028928 * 25    8700723200                                10 00000110100110101000000000000000     110788608
  110788608 * 26    2880503808                                   10101011101100010000000000000000   -1414463488
-1414463488 * 27  -38190514176  11111111111111111111111111110111 00011011101010110000000000000000     464191488
  464191488 * 28   12997361664                                11 00000110101101000000000000000000     112459776
  112459776 * 29    3261333504                                   11000010011001000000000000000000   -1033633792
-1033633792 * 30  -31009013760  11111111111111111111111111111000 11000111101110000000000000000000    -944242688
 -944242688 * 31  -29271523328  11111111111111111111111111111001 00101111010010000000000000000000     793247744
  793247744 * 32   25383927808                               101 11101001000000000000000000000000    -385875968
 -385875968 * 33  -12733906944  11111111111111111111111111111101 00001001000000000000000000000000     150994944
  150994944 * 34    5133828096                                 1 00110010000000000000000000000000     838860800
  838860800 * 35   29360128000                               110 11010110000000000000000000000000    -704643072
 -704643072 * 36  -25367150592  11111111111111111111111111111010 00011000000000000000000000000000     402653184
  402653184 * 37   14898167808                                11 01111000000000000000000000000000    2013265920
 2013265920 * 38   76504104960                             10001 11010000000000000000000000000000    -805306368
 -805306368 * 39  -31406948352  11111111111111111111111111111000 10110000000000000000000000000000   -1342177280
-1342177280 * 40  -53687091200  11111111111111111111111111110011 10000000000000000000000000000000   -2147483648
-2147483648 * 41  -88046829568  11111111111111111111111111101011 10000000000000000000000000000000   -2147483648
-2147483648 * 42  -90194313216  11111111111111111111111111101011 00000000000000000000000000000000             0
          0 * 43             0                                                                  0             0
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
          0 * 98             0                                                                  0             0
  1. est le résultat correct
  2. est la représentation interne du résultat (64 bits sont utilisés pour l'illustration)
  3. est le résultat représenté par le complément à deux des 32 bits inférieurs

Nous savons que multiplier un nombre par un nombre pair:

  • décale les bits vers la gauche et ajoute zéro bit vers la droite
  • donne un nombre pair

Donc, fondamentalement, votre programme multiplie un nombre pair avec un autre nombre à plusieurs reprises, ce qui remet à zéro les bits de résultat en commençant par la droite.

PS: Si les multiplications n'impliquent que des nombres impairs, le résultat ne deviendra pas nul.


15
La représentation hexadécimale est ce qui m'a aidé à comprendre ce qui se passait ici. Merci de clarifier!

1
Oui, ce serait plus instructif si vous modifiiez votre programme pour imprimer également les valeurs hexadécimales de la longue liste.
Hot Licks

4
Cette réponse est correcte mais il y a tellement de désordre. Les cinq dernières lignes en sont le cœur, et nulle part elles n'illustrent vraiment où exactement cela entre en jeu. (Mais on peut le résoudre à partir de la table géante.)
Rex Kerr

6
En d'autres termes, vous accumulez des facteurs de 2. Certains nombres vous donnent plusieurs facteurs de 2 à eux seuls, comme 12, 16 et 20. Chaque facteur de 2 décale à droite tous les bits de tous vos résultats ultérieurs, laissant des zéros comme espaces réservés. Une fois que vous avez décalé 32 fois vers la droite, il ne vous reste plus que 32 zéros d'espace réservé.
Keen

2
Un effet similaire peut également être observé en base 10. Essayez de multiplier n'importe quelle série d'entiers consécutifs, chaque fois que vous multipliez par un nombre divisible par 10, vous ajoutez au moins un zéro à la fin du produit, et il est impossible de supprimer ce zéro à partir du produit par multiplication d'entiers. À un moment donné, tous les n-ième chiffres les moins significatifs seront remplis de zéros et si vous faites l'arithmétique à un modulo 10 ** m (ce qui a pour effet de couper tout sauf les m-ièmes chiffres les moins significatifs), puis il finira par tourner à zéro. De même avec toutes les autres bases.
Lie Ryan

70

La multiplication des ordinateurs se produit vraiment modulo 2 ^ 32. Une fois que vous avez accumulé suffisamment de puissances de deux dans le multiplicande, toutes les valeurs seront 0.

Ici, nous avons tous les nombres pairs de la série, ainsi que la puissance maximale de deux qui divise le nombre et la puissance cumulée de deux

num   max2  total
10    2     1
12    4     3
14    2     4
16    16    8
18    2     9
20    4    11
22    2    12
24    8    15
26    2    16
28    4    18
30    2    19
32    32   24
34    2    25
36    4    27
38    2    28
40    8    31
42    2    32

Le produit jusqu'à 42 est égal à x * 2 ^ 32 = 0 (mod 2 ^ 32). La séquence des puissances de deux est liée aux codes Gray (entre autres) et apparaît sous la forme https://oeis.org/A001511 .

EDIT: pour voir pourquoi les autres réponses à cette question sont incomplètes, considérez le fait que le même programme, restreint aux entiers impairs uniquement, ne convergerait pas vers 0, malgré tout le débordement.


Yay! Enfin, la bonne réponse. Les gens devraient remarquer cette réponse plus!
Rex Kerr

C'est la seule bonne réponse. Tous les autres n'expliquent pas pourquoi .
Olivier Grégoire

5
@ OlivierGrégoire Je ne suis pas d'accord; Je pense que la réponse acceptée est correcte et donne une très bonne explication. Celui-ci est juste plus direct.
David Z

1
J'espère que plus de gens verront cette réponse. La cause profonde est indiquée ici!
lanpa

1
@DavidZ: D'accord; la réponse acceptée est généralement correcte - mon message n'aborde pas vraiment le "pourquoi" de ma phrase d'ouverture. Mais la fin de la réponse acceptée est la chose la plus proche d'une réponse à "pourquoi zéro", mais elle n'explique pas "pourquoi 42" - il n'y a que 16 nombres pairs entre 10 et 42
user295691

34

Cela ressemble à un débordement d'entier .

Regarde ça

BigDecimal product=new BigDecimal(1);
for(int i=10;i<99;i++){
    product=product.multiply(new BigDecimal(i));
}
System.out.println(product);

Production:

25977982938941930515945176761070443325092850981258133993315252362474391176210383043658995147728530422794328291965962468114563072000000000000000000000

La sortie n'est plus une intvaleur. Ensuite, vous obtiendrez une valeur erronée à cause du débordement.

S'il déborde, il revient à la valeur minimale et continue à partir de là. S'il sous-déborde, il revient à la valeur maximale et continue à partir de là.

Plus d' info

Modifier .

Modifions votre code comme suit

int product = 1;
for (int i = 10; i < 99; i++) {
   product *= i;
   System.out.println(product);
}

Production:

10
110
1320
17160
240240
3603600
57657600
980179200
463356416
213837312
-18221056
-382642176
171806720
-343412736
348028928
110788608
-1414463488
464191488
112459776
-1033633792
-944242688
793247744
-385875968
150994944
838860800
-704643072
402653184
2013265920
-805306368
-1342177280
-2147483648
-2147483648>>>binary representation is 11111111111111111111111111101011 10000000000000000000000000000000 
 0 >>> here binary representation will become 11111111111111111111111111101011 00000000000000000000000000000000 
 ----
 0

22

C'est à cause d'un débordement d'entier. Lorsque vous multipliez plusieurs nombres pairs ensemble, le nombre binaire obtient beaucoup de zéros de fin. Lorsque vous avez plus de 32 zéros de fin pour un int, il passe à 0.

Pour vous aider à visualiser cela, voici les multiplications en hexadécimal calculées sur un type de nombre qui ne débordera pas. Voyez comment les zéros de fin grandissent lentement et notez que an intest composé des 8 derniers chiffres hexadécimaux. Après avoir multiplié par 42 (0x2A), les 32 bits de an intsont des zéros!

                                     1 (int: 00000001) * 0A =
                                     A (int: 0000000A) * 0B =
                                    6E (int: 0000006E) * 0C =
                                   528 (int: 00000528) * 0D =
                                  4308 (int: 00004308) * 0E =
                                 3AA70 (int: 0003AA70) * 0F =
                                36FC90 (int: 0036FC90) * 10 =
                               36FC900 (int: 036FC900) * 11 =
                              3A6C5900 (int: 3A6C5900) * 12 =
                             41B9E4200 (int: 1B9E4200) * 13 =
                            4E0CBEE600 (int: 0CBEE600) * 14 =
                           618FEE9F800 (int: FEE9F800) * 15 =
                          800CE9315800 (int: E9315800) * 16 =
                         B011C0A3D9000 (int: 0A3D9000) * 17 =
                        FD1984EB87F000 (int: EB87F000) * 18 =
                      17BA647614BE8000 (int: 14BE8000) * 19 =
                     25133CF88069A8000 (int: 069A8000) * 1A =
                    3C3F4313D0ABB10000 (int: ABB10000) * 1B =
                   65AAC1317021BAB0000 (int: 1BAB0000) * 1C =
                  B1EAD216843B06B40000 (int: 06B40000) * 1D =
                142799CC8CFAAFC2640000 (int: C2640000) * 1E =
               25CA405F8856098C7B80000 (int: C7B80000) * 1F =
              4937DCB91826B2802F480000 (int: 2F480000) * 20 =
             926FB972304D65005E9000000 (int: E9000000) * 21 =
           12E066E7B839FA050C309000000 (int: 09000000) * 22 =
          281CDAAC677B334AB9E732000000 (int: 32000000) * 23 =
         57BF1E59225D803376A9BD6000000 (int: D6000000) * 24 =
        C56E04488D526073CAFDEA18000000 (int: 18000000) * 25 =
      1C88E69E7C6CE7F0BC56B2D578000000 (int: 78000000) * 26 =
     43C523B86782A6DBBF4DE8BAFD0000000 (int: D0000000) * 27 =
    A53087117C4E76B7A24DE747C8B0000000 (int: B0000000) * 28 =
  19CF951ABB6C428CB15C2C23375B80000000 (int: 80000000) * 29 =
 4223EE1480456A88867C311A3DDA780000000 (int: 80000000) * 2A =
AD9E50F5D0B637A6610600E4E25D7B00000000 (int: 00000000)

1
C'est un peu trompeur. Bien qu'il démontre correctement pourquoi il passe à zéro, chaque valeur est conservée dans un entier 32 bits après la multiplication, elle doit donc être tronquée après chaque étape. La façon dont vous avez écrit votre réponse implique qu'elle n'est pas tronquée tant que la boucle for n'est pas terminée. Ce serait mieux si vous ne montriez que les 8 derniers chiffres de chaque étape.
RyNo

@KamikazeScotsman J'ai amélioré ma réponse en fonction de votre suggestion. Moins de zéros redondants, plus de visibilité int 32 bits.
Tim S.

1
+1 pour afficher la valeur réelle par rapport à la valeur 32 bits à chaque étape, en soulignant que la valeur est tronquée ...
kwah

14

Quelque part au milieu, vous obtenez 0le produit. Ainsi, votre produit entier sera 0.

Dans ton cas :

for (int i = 10; i < 99; i++) {
    if (product < Integer.MAX_VALUE)
        System.out.println(product);
    product *= i;
}
// System.out.println(product);

System.out.println(-2147483648 * EvenValueOfi); // --> this is the culprit (Credits : Kocko's answer )

O/P :
1
10
110
1320
17160
240240
3603600
57657600
980179200
463356416
213837312
-18221056
-382642176
171806720
-343412736
348028928
110788608
-1414463488
464191488
112459776
-1033633792
-944242688
793247744
-385875968
150994944
838860800
-704643072
402653184
2013265920
-805306368
-1342177280  --> Multiplying this and the current value of `i` will also give -2147483648 (INT overflow)
-2147483648  --> Multiplying this and the current value of `i` will also give -2147483648 (INT overflow)

-2147483648  ->  Multiplying this and the current value of 'i' will give 0 (INT overflow)
0
0
0

Chaque fois que vous multipliez la valeur actuelle de ipar le nombre que vous obtenez 0en sortie.


@KickButtowski - Multipliez les nombres .. Vous saurez pourquoi: P
TheLostMind

@KickButtowski - 0 multiplié par tout autre nombre se traduira constamment par 0 pour toujours après que le débordement retourne 0 à tout moment.
Mr Moose

Je l'ai fait mais je pense que vous devriez être plus informatif pour que les autres puissent aussi apprendre
Kick Buttowski

@KickButtowski - a mis à jour la réponse. Vérifiez la partie OP.
TheLostMind

8
@KickButtowski: C'est parce que le débordement se produit à une puissance de deux. Essentiellement, l'OP calcule {10 x 11 x 12 x ... x 98} modulo 2 ^ 32. Étant donné que les multiples de 2 apparaissent bien plus de 32 fois dans ce produit, le résultat est zéro.
ruakh

12

Étant donné que la plupart des réponses existantes pointent vers les détails d'implémentation de Java et la sortie de débogage, examinons les mathématiques derrière la multiplication binaire pour vraiment répondre au pourquoi.

Le commentaire de @kasperd va dans le bon sens. Supposons que vous ne multipliez pas directement avec le nombre mais avec les facteurs premiers de ce nombre à la place. De nombreux nombres auront 2 comme facteur premier. En binaire, cela équivaut à un décalage vers la gauche. Par commutativité, nous pouvons multiplier par des facteurs premiers de 2 en premier. Cela signifie que nous faisons juste un décalage vers la gauche.

En examinant les règles de multiplication binaire, le seul cas où un 1 entraînera une position de chiffre spécifique est lorsque les deux valeurs d'opérande sont une.

Ainsi, l'effet d'un décalage vers la gauche est que la position de bit la plus basse d'un 1 lors de la multiplication supplémentaire du résultat est augmentée.

Puisque l'entier ne contient que les bits d'ordre le plus bas, ils seront tous mis à 0 lorsque le facteur premier 2 est assez souvent inclus dans le résultat.

Notez que la représentation du complément à deux n'est pas intéressante pour cette analyse, car le signe du résultat de la multiplication peut être calculé indépendamment du nombre résultant. Cela signifie que si la valeur déborde et devient négative, les bits de poids faible sont représentés par 1, mais lors de la multiplication, ils sont à nouveau traités comme étant 0.


7

Si j'exécute ce code, ce que j'obtiens tout -

          1 * 10 =          10
         10 * 11 =         110
        110 * 12 =        1320
       1320 * 13 =       17160
      17160 * 14 =      240240
     240240 * 15 =     3603600
    3603600 * 16 =    57657600
   57657600 * 17 =   980179200
  980179200 * 18 =   463356416 <- Integer Overflow (17643225600)
  463356416 * 19 =   213837312
  213837312 * 20 =   -18221056
  -18221056 * 21 =  -382642176
 -382642176 * 22 =   171806720
  171806720 * 23 =  -343412736
 -343412736 * 24 =   348028928
  348028928 * 25 =   110788608
  110788608 * 26 = -1414463488
-1414463488 * 27 =   464191488
  464191488 * 28 =   112459776
  112459776 * 29 = -1033633792
-1033633792 * 30 =  -944242688
 -944242688 * 31 =   793247744
  793247744 * 32 =  -385875968
 -385875968 * 33 =   150994944
  150994944 * 34 =   838860800
  838860800 * 35 =  -704643072
 -704643072 * 36 =   402653184
  402653184 * 37 =  2013265920
 2013265920 * 38 =  -805306368
 -805306368 * 39 = -1342177280
-1342177280 * 40 = -2147483648
-2147483648 * 41 = -2147483648
-2147483648 * 42 =           0 <- produce 0 
          0 * 43 =           0

Cause de dépassement d'entier -

980179200 * 18 =   463356416 (should be 17643225600)

17643225600 : 10000011011100111100100001000000000 <-Actual
MAX_Integer :     1111111111111111111111111111111
463356416   :     0011011100111100100001000000000 <- 32 bit Integer

Produire 0 cause -

-2147483648 * 42 =           0 (should be -90194313216)

-90194313216: 1010100000000000000000000000000000000 <- Actual
MAX_Integer :       1111111111111111111111111111111
0           :      00000000000000000000000000000000 <- 32 bit Integer

6

Finalement, le calcul déborde, et finalement ce débordement conduit à un produit de zéro; cela arrive quand product == -2147483648et i == 42. Essayez ce code pour le vérifier par vous-même (ou exécutez le code ici ):

import java.math.BigInteger;

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        System.out.println("Result: " + (-2147483648 * 42));
    }
}

Une fois qu'il est nul, il reste bien sûr nul. Voici un code qui produira un résultat plus précis (vous pouvez exécuter le code ici ):

import java.math.BigInteger;

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        BigInteger p = BigInteger.valueOf(1);
        BigInteger start = BigInteger.valueOf(10);
        BigInteger end = BigInteger.valueOf(99);
        for(BigInteger i = start; i.compareTo(end) < 0; i = i.add(BigInteger.ONE)){
            p = p.multiply(i);
            System.out.println("p: " + p);
        }
        System.out.println("\nProduct: " + p);
    }
}

Il déborde (au sens précis du terme) bien avant la 42e itération - à 19 il est déjà survolé, puisque f (19) <f (18)
user295691

Oui, mais le débordement n'entraîne ni n'aboutit à un produit de zéro jusqu'à la 42e itération.
Trevor

Je suppose que ce que je veux dire, c'est que vous ne répondez pas au «pourquoi» - pourquoi le produit cumulatif passerait-il jamais par 0? La réponse de Tim S. donne quelques indications sur pourquoi, mais la vraie réponse réside dans l'arithmétique modulaire.
user295691

La question ne demande pas pourquoi le produit passe par zéro. Il demande pourquoi le code produit zéro. En d'autres termes, je pense que l'OP s'intéresse plus à la dynamique du langage Java qu'à l'arithmétique modulaire, mais peut-être que je me trompe. Ce ne serait pas la première fois que j'interprétais mal la question de quelqu'un.
Trevor

par exemple, si ce programme avait pris le produit de tous les nombres impairs de 11 à 99, alors il n'atteindrait pas zéro. Votre réponse ne répond pas vraiment aux raisons pour lesquelles cela se produirait.
user295691

1

C'est un débordement d'entier.

Le type de données int est de 4 octets ou 32 bits. Par conséquent, les nombres supérieurs à 2 ^ (32 - 1) - 1 (2 147 483 647) ne peuvent pas être stockés dans ce type de données. Vos valeurs numériques seront incorrectes.

Pour les très grands nombres, vous voudrez importer et utiliser la classe java.math.BigInteger:

BigInteger product = BigInteger.ONE;
for (long i = 10; i < 99; i++) 
    product = product.multiply(BigInteger.valueOf(i));
System.out.println(product.toString());

REMARQUE: Pour les valeurs numériques qui sont encore trop grandes pour le type de données int, mais suffisamment petites pour tenir dans 8 octets (valeur absolue inférieure ou égale à 2 ^ (64 - 1) - 1), vous devriez probablement utiliser la longprimitive.

Les problèmes de pratique de HackerRank (www.hackerrank.com), tels que la section de pratique des algorithmes ( https://www.hackerrank.com/domains/algorithms/warmup ) incluent de très bonnes questions en grand nombre qui donnent de bonnes pratiques sur la façon de pensez au type de données approprié à utiliser.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.