2010-08-14 21 views
8

Perché il codice sottostante stampa 2147483647, il valore effettivo è 2147483648?Domanda di base su Java int

i = (int)Math.pow(2,31) ; 
    System.out.println(i); 

Capisco che il valore positivo massimo che un int può contenere è 2147483647. Poi perché un codice come questo auto avvolge il lato negativo e stampe -2147483648?

i = (int)Math.pow(2,31) +1 ; 
System.out.println(i); 

I è di tipo Integer. Se il secondo esempio di codice (aggiunta di due numeri interi) può avvolgere sul lato negativo se il risultato esce dal range positivo, perché il primo campione non può essere avvolto? Inoltre,

i = 2147483648 +1 ; 
System.out.println(i); 

che è molto simile al secondo esempio di codice tiri compilazione di errore che dice il primo letterale è fuori portata intero? La mia domanda è, come per il secondo esempio di codice, perché il primo e il terzo campione non possono eseguire il wrapping automatico dall'altra parte?

+0

Per chiarimenti, questo non ha nulla a che fare con 'java.lang.Integer', che è diverso da' int'. – polygenelubricants

+1

Come importa? Il problema (o la domanda) sarà lo stesso anche se scrivo il cast su (Integer) piuttosto che int. – chedine

risposta

12

Per il primo esempio di codice, il risultato viene ridotto da double a int. il JLS 5.1.3 descrive il modo in cui vengono eseguite le conversioni di restringimento per i duplicati in interi.

La parte rilevante è:

Il valore deve essere troppo grande (un valore positivo di grandi dimensioni o infinito positivo), e il risultato della il primo passo è la più grande valore rappresentabile digitare int o lungo.

Questo è il motivo per cui 2^31 (2147483648) viene ridotto a Integer.MAX_VALUE (2147483647).Lo stesso vale per

i = (int)(Math.pow(2,31)+100.0) ; // addition note the parentheses 

e

i = (int)10000000000.0d; // == 2147483647 

Quando l'aggiunta è fatto senza parentesi, come nel tuo secondo esempio, siamo quindi di fronte ad oltre intero. I tipi integrali utilizzano 2's complement per rappresentare i valori. Nell'ambito di questo regime aggiungendo 1 al

0x7FFFFFFF (2147483647) 

0x80000000 

Qual è complemento a 2 per -2147483648. Alcune lingue eseguono il controllo di overflow per le operazioni aritmetiche (ad esempio, Ada genererà un'eccezione). Java, con il suo patrimonio C non controlla l'overflow. Le CPU tipicamente impostano uno overflow flag quando un'operazione aritmetica trabocca o underflow. I runtime linguistici possono controllare questo flag, sebbene questo introduca un overhead aggiuntivo, che alcuni ritengono non necessario.

Il terzo esempio non viene compilato poiché il compilatore verifica i valori letterali rispetto all'intervallo del loro tipo e fornisce un errore del compilatore per i valori fuori intervallo. Vedi JLS 3.10.1 - Integer Literals.

+0

Non è '2147483647 = 0x7FFFFFFF' e' -2147483648 = 0x80000000'? – ILMTitan

+0

@ILMTitan: è corretto, ed è quello che pensavo di aver scritto, ma vedo che avrei scritto qualcos'altro. Ora è corretto. – mdma

4

Quindi perché un codice come questo viene automaticamente spostato sul lato negativo e stampa -2147483648?

Questo è chiamato overflow. Java lo fa perché C lo fa. C lo fa perché la maggior parte dei processori lo fa. In alcune lingue questo non succede. Ad esempio alcune lingue genereranno un'eccezione, in altre il tipo cambierà in qualcosa che può contenere il risultato.

La mia domanda è, come per il secondo esempio di codice, perché non è possibile eseguire il primo e il terzo campionamento automatico dall'altra parte?

Per quanto riguarda il primo programma: Math.pow restituisce un doppio e non trabocchi. Quando il doppio viene convertito in un numero intero, viene troncato.

Riguardo al terzo programma: l'overflow è raramente una proprietà desiderabile ed è spesso un segno che il programma non funziona più. Se il compilatore può vedere che ottiene un overflow solo dalla valutazione di una costante che è quasi certamente un errore nel codice. Se hai desiderato un numero negativo di grandi dimensioni, perché dovresti scrivere un grande positivo?