2015-06-02 16 views
17
long m = 24 * 60 * 60 * 1000 * 1000; 

Il codice sopra riportato crea overflow e non stampa il risultato corretto.Overflow si verifica con la moltiplicazione

long m2 = 24L * 60 * 60 * 1000 * 1000; 
long m3 = 24 * 60 * 60 * 1000 * 1000L; 

Le 2 righe precedenti stampano il risultato corretto.

Le mie domande sono-

  1. importa a compilatore che io uso, m2 o m3?
  2. In che modo java inizia a moltiplicarsi? Da sinistra a destra o da destra a sinistra? Il 24 * 60 viene calcolato per primo o 1000 * 1000?
+1

oops- long m2 = 24L * 60 * 60 * 1000 * 1000 * 1000 * 1000; long m3 = 24 * 60 * 60 * 1000 * 1000 * 1000 * 1000L; m2 e m3 non danno lo stesso risultato quando più volte si dice una moltiplicazione di un fattore di 1000 * 1000. Quindi sembra che la moltiplicazione avvenga da sinistra a destra. – rents

+2

A destra, usare 'm2' in modo che ogni moltiplicazione intermedia sia promossa a' long'. La moltiplicazione è sinistra-associativa, quindi va da sinistra a destra. – GriffeyDog

+0

La moltiplicazione è associativa, quindi l'ordine non avrebbe importanza. Tuttavia è calcolato da sinistra a destra nei casi in cui conta come chiamare i metodi che restituiscono un numero. –

risposta

16

Vorrei utilizzare la riga m2 anziché la riga m3.

Java valuta l'operatore di moltiplicazione * da left to right, pertanto viene valutato per primo.

Si dà il caso che 24 * 60 * 60 * 1000 (uno 1000) non trabocchi, in modo che per il momento si moltiplica per 1000L (il secondo 1000), il prodotto viene promosso a long prima di moltiplicare, in modo che troppo pieno non prende posto.

Tuttavia, come indicato nei commenti, più fattori possono causare un overflow nel tipo di dati int prima di moltiplicare l'ultimo numero long, ottenendo una risposta errata. È preferibile utilizzare un valore letterale long per il primo numero (a sinistra) come in m2 per evitare l'overflow dall'inizio. In alternativa, puoi lanciare il primo valore letterale come long, ad es. (long) 24 * 60 * ....

19

In questo caso -

long m = 24 * 60 * 60 * 1000 * 1000; 

Il diritto di assegnazione viene valutata per prima. A destra non ci sono dati di tipo long. Tutti sono int. Quindi lo JVM prova ad adattare il risultato in un int quindi si è verificato l'overflow.

E nel secondo caso -

long m2 = 24L * 60 * 60 * 1000 * 1000; 
long m3 = 24 * 60 * 60 * 1000 * 1000L; 

Ecco un operando della moltiplicazione è long. Quindi altri vengono richiesti automaticamente a long. Il risultato sta cercando di adattarsi a un long. Finalmente l'assegnazione è fatta con m2 e m3.

E sì l'associatività della moltiplicazione da sinistra a destra - significa che l'operando di sinistra viene preso per primo. E sulla base di questo fatto credo che in questo scenario dovremmo usare -

long m2 = 24L * 60 * 60 * 1000 * 1000; 

questa affermazione, dal momento che in questa dichiarazione la promozione in long luoghi prese in precedenza, che riduce il rischio di trabocco.

+0

"La sinistra del compito viene valutata per prima." ... intendevi il giusto? – Mints97

+0

C'è ancora un errore di battitura nella seconda frase :) – Ruslan

+0

@Ruslan, penso di avere problemi con left-right :(. Grazie – Razib

6

La moltiplicazione funziona da sinistra a destra e int * int produce int.Così

24 * 60 * 60 * 1000 * 1000 

è stessa

(((24 * 60)* 60) * 1000) * 1000 

che ci dà

(((1440)* 60) * 1000) * 1000 
(( 86400 ) * 1000) * 1000 
( 86400000  ) * 1000 

e, infine, a causa di integer overflow (dal 86400000000 è troppo grande per intero il cui valore massimo è 2147483647) risultato sarà be

500654080 

È possibile eliminare l'overflow di numeri interi utilizzando long come uno degli argomenti (int * long e long produce long).

In questo caso si può fare all'inizio come avete fatto nel caso di m2: 24L * 60 che produrrà long1440L che ancora una volta sarà moltiplicato per int 60 produrre nuova long, e così via, producendo solo long valori.

m3 caso funziona qui perché si stanno moltiplicando 86400000 da 1000L che significa che si sta evitando integer overflow in quanto risultato sarà long.

9

Since expressions are evaluated from left to right, preferirei la prima soluzione (m2 = ...).

Ragionamento: diamo un'occhiata a un esempio leggermente diverso.

long l = Integer.MAX_VALUE * 2 * 2L; 

Questa espressione restituirà -4 poiché soltanto l'ultimo moltiplicazione getta la prima espressione di long (che è -2 a questo punto nel tempo, perché entrambi gli operandi sono int). Se si scrive

long l = Integer.MAX_VALUE * 2L * 2; 

invece, l terrà il valore atteso della 8589934588 fin dalla prima moltiplicazione produce un risultato di tipo long.

4

Moltiplichiamo più numeri, questa linea traboccherà anche c'è un 1000L:

long m3 = 24 * 60 * 60 * 1000 * 1000 * 1000 * 1000L; 

Mentre questo vi darà risultato corretto:

long m3 = 24L * 60 * 60 * 1000 * 1000 * 1000 * 1000; 

quindi siamo sicuri che Java inizia moltiplicando da sinistra a destra e dobbiamo iniziare con Long da sinistra per evitare l'overflow.

2

Questo perché quando viene utilizzato un operando lungo l'altro, tutti gli operandi di tipo int vengono richiesti a long.

L'espressione in java è stata valutata da sinistra a destra.