Perché Java pensa che il prodotto di tutti i numeri da 10 a 99 sia 0?


131

Il seguente blocco di codici fornisce l'output come 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);
    }
}

Per favore qualcuno può spiegare perché questo accade?


106
Molto probabilmente hai un overflow di numeri interi.
TheLostMind

68
Se consideri i fattori primi nel prodotto, dovrai 2presentarti circa 90 volte. Ciò significa che avrai bisogno di una variabile con almeno 90 bit per ottenere un output diverso da zero. 32 e 64 sono entrambi inferiori a 90. Per calcolare numeri interi più grandi delle parole native, devi usare qualunque classe di numeri interi grande sia disponibile nella lingua scelta.
Kasperd,

62
Tecnicamente, questo è il prodotto di numeri da 10 a 98.
AShelly,

45
Che cosa? Perché questa domanda è stata chiusa come duplicato di una domanda che è stata chiusa come duplicato di questa domanda ?
Salman A

82
99 problemi e 2147483648 non sono 1.
glenatron,

Risposte:


425

Ecco cosa fa il programma ad ogni passaggio:

          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

Si noti che su alcuni passaggi la moltiplicazione si traduce in un numero inferiore (980179200 * 18 = 463356416) o in un segno errato (213837312 * 20 = -18221056), indicando che si è verificato un overflow di numeri interi. Ma da dove viene lo zero? Continuare a leggere.

Tenendo presente che inttipo di dati è un 32-bit con segno , complemento a due interi, qui è una spiegazione di ogni passaggio:

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. è il risultato corretto
  2. è la rappresentazione interna del risultato (64 bit sono usati per l'illustrazione)
  3. è il risultato rappresentato dal complemento a due dei 32 bit inferiori

Sappiamo che moltiplicare un numero per un numero pari:

  • sposta i bit verso sinistra e aggiunge zero bit verso destra
  • risulta in un numero pari

Quindi sostanzialmente il tuo programma moltiplica ripetutamente un numero pari con un altro numero che azzera i bit di risultato a partire da destra.

PS: se le moltiplicazioni riguardavano solo numeri dispari, il risultato non diventerà zero.


15
La Rappresentazione esadecimale è ciò che mi ha aiutato a capire cosa stava succedendo qui. Grazie per il chiarimento!

1
Sì, sarebbe più istruttivo se modificassi il tuo programma per stampare anche i valori esadecimali nella lunga lista.
Hot Licks,

4
Questa risposta è corretta ma c'è così tanto disordine. Le ultime cinque righe ne sono il fulcro, e da nessuna parte illustra davvero dove esattamente ciò entri in gioco. (Ma si può scovare dal tavolo gigante.)
Rex Kerr,

6
In altre parole, accumuli fattori di 2. Alcuni numeri ti danno più fattori di 2 tutti da soli, come 12, 16 e 20. Ogni fattore di 2 sposta a destra tutti i bit di tutti i risultati successivi, lasciando gli zero come segnaposto. Dopo aver spostato a destra 32 volte, ti rimane solo 32 zero segnaposto.
Appassionato il

2
Un effetto simile si può vedere anche nella base 10. Prova a moltiplicare qualsiasi serie di numeri interi consecutivi, ogni volta che moltiplichi per un numero divisibile per 10, aggiungi almeno uno zero alla fine del prodotto ed è impossibile rimuovere quello zero dal prodotto moltiplicando gli interi. Ad un certo punto, tutte le cifre n meno significative verranno riempite di zero e se si sta eseguendo l'aritmetica in un modulo 10 ** m (che ha l'effetto di tagliare tutto tranne le cifre m meno significative), poi finirà per girare a zero. Allo stesso modo con qualsiasi altra base.
Lie Ryan,

70

La moltiplicazione del computer sta realmente accadendo modulo 2 ^ 32. Dopo aver accumulato abbastanza potenze di due nel multiplicando, tutti i valori saranno 0.

Qui abbiamo tutti i numeri pari della serie, insieme alla potenza massima di due che divide il numero e alla potenza cumulativa di due

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

Il prodotto fino a 42 è uguale a x * 2 ^ 32 = 0 (mod 2 ^ 32). La sequenza dei poteri di due è correlata ai codici Gray (tra le altre cose) e appare come https://oeis.org/A001511 .

EDIT: per vedere perché le altre risposte a questa domanda sono incomplete, considera il fatto che lo stesso programma, limitato solo a numeri dispari, non converrebbe a 0, nonostante tutto lo straripamento.


Sìì! Finalmente la risposta corretta. Le persone dovrebbero notare di più questa risposta!
Rex Kerr,

Questa è l'unica risposta corretta. Tutti gli altri non spiegano perché .
Olivier Grégoire,

5
@ OlivierGrégoire Non sono d'accordo; Penso che la risposta accettata sia corretta e dia una spiegazione perfettamente valida. Questo è solo più diretto.
David Z,

1
Spero che più persone vedano questa risposta. La causa principale è indicata qui!
lanpa,

1
@DavidZ: concordato; la risposta accettata è per lo più corretta - il mio post non si occupa in realtà del "perché" della mia frase di apertura. Ma la chiusura della risposta accettata è la cosa più vicina a una risposta a "why zero", ma non spiega "why 42" - ci sono solo 16 numeri pari tra 10 e 42
user295691

34

Sembra un overflow di numeri interi .

Guarda questo

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

Produzione:

25977982938941930515945176761070443325092850981258133993315252362474391176210383043658995147728530422794328291965962468114563072000000000000000000000

L'output non sarà più a int valore. Quindi otterrai un valore errato a causa dell'overflow.

Se trabocca, torna al valore minimo e continua da lì. Se underflow, torna al valore massimo e continua da lì.

Più informazioni

modificare .

Cambiamo il tuo codice come segue

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

Produzione:

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

È a causa dell'overflow di numeri interi. Quando moltiplichi molti numeri pari insieme, il numero binario ottiene molti zeri finali. Quando hai oltre 32 zero finali per un int, passa a0 .

Per aiutarti a visualizzarlo, ecco le moltiplicazioni in esadecimale calcolate su un tipo di numero che non trabocca. Guarda come crescono lentamente gli zeri finali e nota che un intè composto dalle ultime 8 cifre esadecimali. Dopo aver moltiplicato per 42 (0x2A), tutti i 32 bit di un intsono zero!

                                     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
Questo è un po 'fuorviante. Mentre dimostra correttamente perché va a zero, ogni valore viene mantenuto in un int a 32 bit dopo la moltiplicazione, quindi dovrebbe essere troncato dopo ogni passaggio. Il modo in cui hai scritto la tua risposta implica che non viene troncata fino al termine del ciclo for. Sarebbe meglio se mostrassi solo le ultime 8 cifre per ogni passaggio.
Ry No

@KamikazeScotsman Ho migliorato la mia risposta in base al tuo suggerimento. Zeri meno ridondanti, maggiore visibilità int a 32 bit.
Tim S.

1
+1 per mostrare il valore effettivo contro il valore a 32 bit su ogni stadio, evidenziando che il valore viene troncato ...
kwah,

14

Da qualche parte nel mezzo ottieni 0come prodotto. Quindi, l'intero prodotto sarà 0.

Nel tuo caso :

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

Ogni volta che moltiplichi il valore corrente di iper il numero che ottieni 0come output.


@KickButtowski - Moltiplica i numeri ..
Saprai

@KickButtowski - 0 moltiplicato per qualsiasi altro numero comporterà costantemente 0 per sempre dopo che l'overflow restituisce 0 in qualsiasi punto.
Mr Moose,

L'ho fatto ma penso che dovresti essere più istruttivo in modo che anche altri possano imparare
Kick Buttowski,

@KickButtowski: aggiornata la risposta. Controllare la parte OP.
TheLostMind

8
@KickButtowski: è perché il trabocco avviene a una potenza di due. In sostanza, l'OP sta elaborando {10 x 11 x 12 x ... x 98} modulo 2 ^ 32. Poiché i multipli di 2 compaiono più di 32 volte in quel prodotto, il risultato è zero.
Ruakh,

12

Poiché molte delle risposte esistenti puntano ai dettagli di implementazione di Java e dell'output di debug, diamo un'occhiata alla matematica alla base della moltiplicazione binaria per rispondere davvero al perché.

Il commento di @kasperd va nella giusta direzione. Supponiamo di non moltiplicare direttamente con il numero ma con i fattori primi di quel numero. Quindi molti numeri avranno 2 come fattore primo. In binario questo equivale a uno spostamento a sinistra. Per commutatività possiamo moltiplicare per primi i fattori 2. Ciò significa che facciamo solo un turno di sinistra.

Quando si osservano le regole di moltiplicazione binaria, l'unico caso in cui un 1 si tradurrà in una posizione di cifra specifica è quando entrambi i valori di operando sono uno.

Quindi l'effetto di uno spostamento a sinistra è che la posizione del bit più basso di 1 aumentando ulteriormente il risultato.

Poiché l'intero contiene solo i bit di ordine più basso, tutti saranno impostati su 0 quando il fattore primo 2 è compreso abbastanza spesso nel risultato.

Si noti che la rappresentazione del complemento a due non è interessante per questa analisi, poiché il segno del risultato della moltiplicazione può essere calcolato indipendentemente dal numero risultante. Ciò significa che se il valore trabocca e diventa negativo, i bit di ordine più basso vengono rappresentati come 1, ma durante la moltiplicazione vengono nuovamente trattati come 0.


7

Se eseguo questo codice Cosa ottengo tutto -

          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

Causa Overflow intero -

980179200 * 18 =   463356416 (should be 17643225600)

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

Produci 0 causa -

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

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

6

Alla fine, il calcolo trabocca e alla fine quel trabocco porta a un prodotto pari a zero; succede quando product == -2147483648e i == 42. Prova questo codice per verificarlo tu stesso (o esegui il codice qui ):

import java.math.BigInteger;

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

Una volta che è zero, ovviamente rimane zero. Ecco un po 'di codice che produrrà un risultato più accurato (puoi eseguirlo qui ):

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);
    }
}

Trabocca (nel senso preciso della parola) ben prima della 42a iterazione - a 19 è già traboccato, poiché f (19) <f (18)
user295691

Sì, ma l'overflow non porta a un risultato pari o uguale a zero fino alla 42a iterazione.
Trevor,

Immagino che ciò a cui sto arrivando è che non ti occupi del "perché" - perché il prodotto cumulativo dovrebbe mai passare attraverso lo 0? La risposta di Tim S. fornisce alcune indicazioni del perché, ma la vera risposta sta nell'aritmetica modulare.
user295691

La domanda non chiede perché il prodotto passa attraverso lo zero. Si chiede perché il codice produca zero. In altre parole, penso che l'OP sia più interessato alla dinamica del linguaggio Java che all'aritmetica modulare, ma forse mi sbaglio. Non sarebbe la prima volta che ho frainteso la domanda di qualcuno.
Trevor,

ad esempio, se questo programma avesse portato il prodotto di tutti i numeri dispari da 11 a 99, allora non raggiungerebbe lo zero. La tua risposta non affronta davvero il motivo per cui ciò potrebbe accadere.
user295691

1

È un overflow di numeri interi.

Il tipo di dati int è 4 byte o 32 bit. Pertanto, i numeri maggiori di 2 ^ (32 - 1) - 1 (2.147.483.647) non possono essere memorizzati in questo tipo di dati. I tuoi valori numerici non saranno corretti.

Per numeri molto grandi, vorrai importare e utilizzare 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());

NOTA: per valori numerici che sono ancora troppo grandi per il tipo di dati int, ma abbastanza piccoli da contenere entro 8 byte (valore assoluto inferiore o uguale a 2 ^ (64 - 1) - 1), è consigliabile utilizzare la longprimitiva.

I problemi di pratica di HackerRank (www.hackerrank.com), come la sezione di esercitazioni sugli algoritmi, ( https://www.hackerrank.com/domains/algorithms/warmup ) includono alcune ottime domande a grandi numeri che danno buone pratiche su come pensa al tipo di dati appropriato da usare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.