Perché queste due operazioni di moltiplicazione danno risultati diversi?

Perché devo aggiungere una lettera “L” per ottenere il valore lungo corretto? E qual è l’altro valore?

long oneYearWithL = 1000*60*60*24*365L; long oneYearWithoutL = 1000*60*60*24*365; System.out.println(oneYearWithL);//gives correct calculation result : 31536000000 System.out.println(oneYearWithoutL)//gives incorrect calculation result: 1471228928 

     long oneYearWithL = 1000*60*60*24*365L; long oneYearWithoutL = 1000*60*60*24*365; 

    Il tuo primo valore è in realtà un lungo (Poiché 365L è un long e 1000*60*60*24 è un integer , quindi il risultato di multiplying un valore long con un valore integer è un valore long .

    Ma il 2 ° valore è un numero intero (Poiché si sta moltiplicando un valore integer con un solo valore integer , quindi il risultato sarà un numero intero a 32-bit . Ora il risultato ottenuto per tale multiplication è al di fuori dell’intervallo reale dell’intero. assegnato alla variabile, viene troncato per adattarsi all’intero intervallo valido.

    Dai un’occhiata alla seguente dichiarazione di stampa: –

     System.out.println(1000*60*60*24*365L); System.out.println(1000*60*60*24*365); System.out.println(Integer.MAX_VALUE); 

    Quando esegui il codice sopra: –

    Produzione: –

     31536000000 1471228928 2147483647 

    Quindi, puoi vedere la differenza ..

     011101010111101100010010110000000000 -- Binary equivalent of 1000*60*60*24*365L 01111111111111111111111111111111 -- Binary equivalent of Integer.MAX_VALUE 

    Quindi, se non aggiungi L alla fine del tuo numero, il 4 bit più significativo viene rimosso dalla prima stringa binaria.

    Quindi, la stringa diventa ..

     (0111)01010111101100010010110000000000 -- Remove the most significant bits.. 01010111101100010010110000000000 -- Binary equivalent of 1471228928 

    (che ottieni come output)


    AGGIORNAMENTO: – Dalla spiegazione sopra, puoi anche capire che, anche nel primo compito, se il risultato della tua multiplication di integers prima di moltiplicarlo con 365L rientra nell’intervallo, sarà di nuovo troncato per rientrare nell’intervallo intero, o convertito in 2's complement representation a 2's complement representation se richiesto, e quindi solo esso sarà moltiplicato con il long value - 365L .

    Ad esempio: –

     long thirtyYearWithL = 1000*60*60*24*30*365L; 

    Nell’esempio sopra, considera la prima parte: 1000*60*60*24*30 . Il risultato di questa moltiplicazione è: – 2592000000 . Ora vediamo ‘come è rappresentato in binary equivalent : –

     2592000000 = 10011010011111101100100000000000 -- MSB is `1`, a negative value 01100101100000010011100000000001 -- 2's complement representation 

    La rappresentazione decimale della rappresentazione del 2's complement è 1702967297 . Quindi, 2592000000 viene convertito in -1702967297 , prima di essere moltiplicato a 365L . Da allora, questo valore rientra nell’intervallo integer range che è: – [-2147483648 to 2147483647] , quindi non verrà troncato ulteriormente.

    Quindi, il risultato effettivo sarà: –

     long thirtyYearWithL = 1000*60*60*24*30*365L; = 2592000000 * 365L; = -1702967297 * 365L = -621583063040 

    Quindi, tutti questi elementi considerano solo il type effettivo di risultato finale quando si applica l’operazione aritmetica. E questo controllo viene eseguito su ogni risultato temporaneo delle operazioni che si sposta da left to right (considerando gli operatori con associatività da left-to-right ). Se qualsiasi risultato temporaneo viene trovato fuori dal raggio d’azione, allora viene convertito di conseguenza per rientrare nell’intervallo richiesto, prima di andare avanti con l’operazione successiva.


    AGGIORNAMENTO 2: –

    Quindi, invece di: –

     long thirtyYearWithL = 1000*60*60*24*30*365L; 

    se muovi il tuo 365L all’inizio, otterrai il risultato corretto: –

     long thirtyYearWithL = 365L*1000*60*60*24*30; // will give you correct result 

    Perché, ora il tuo risultato temporary sarà di tipo long , ed è in grado di mantenere quel valore.

    Senza la L tuo calcolo viene eseguito come valore a 32 bit. Se si esprimono i valori come esadecimali, il valore inferiore è solo i 4 byte inferiori del valore più grande.

    Java ha come valore predefinito il tipo intero a 32 bit. La L , per Long, è a 64 bit. Inserendo L dopo 365 , si sta dicendo al compilatore di considerare 365 come un valore long . Quando i valori a 32 e 64 bit vengono moltiplicati, il compilatore reimposta il valore a 32 bit a 64 bit, in modo che i risultati intermedi nella valutazione dell’espressione mantengano l’intervallo completo a 64 bit.

    Vedi Tipi primari e valori nella specifica del linguaggio Java .

    Il comportamento della moltiplicazione è esplicitamente definito in https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.1 , come segue:

    15.17.1 Operatore di moltiplicazione *

    L’operatore binario * esegue la moltiplicazione, producendo il prodotto dei suoi operandi. La moltiplicazione è un’operazione commutativa se le espressioni di operando non hanno effetti collaterali. Mentre la moltiplicazione dell’intero è associativa quando gli operandi sono tutti dello stesso tipo, la moltiplicazione in virgola mobile non è associativa. Se una moltiplicazione intera è in overflow, il risultato sono i bit di ordine basso del prodotto matematico rappresentati in un formato a due complementi sufficientemente grande. Di conseguenza, se si verifica un overflow, il segno del risultato potrebbe non essere uguale al segno del prodotto matematico dei due valori dell’operando.

    Il risultato di una moltiplicazione in virgola mobile è regolato dalle regole dell’aritmetica IEEE 754:

    • Se uno degli operandi è NaN , il risultato è NaN .
    • Se il risultato non è NaN , il segno del risultato è positivo se entrambi gli operandi hanno lo stesso segno e negativo se gli operandi hanno segni diversi.
    • La moltiplicazione di un infinito per uno zero risulta in NaN.
    • La moltiplicazione di un infinito con un valore finito produce un infinito firmato. Il segno è determinato dalla regola sopra indicata.
    • Nei casi rimanenti, dove non è coinvolto né un infinito né un NaN, viene calcolato il prodotto matematico esatto. Viene quindi scelto un set di valori a virgola mobile:
      • Se l’espressione di moltiplicazione è FP-strict (§15.4):
        • Se il tipo dell’espressione di moltiplicazione è float , deve essere scelto il valore float impostato.
        • Se il tipo dell’espressione di moltiplicazione è double , è necessario selezionare il doppio set di valori.
      • Se l’espressione di moltiplicazione non è FP-strict:
        • Se il tipo dell’espressione di moltiplicazione è float , può essere scelto il set di valori float o il set di valori float-extended-exponent, in base al capriccio dell’implementazione.
        • Se il tipo dell’espressione di moltiplicazione è double , può essere scelto il doppio valore impostato o il doppio valore esteso-esponente, in base al capriccio dell’implementazione.

    Successivamente, un valore deve essere scelto dal valore impostato impostato per rappresentare il prodotto.

    Se la grandezza del prodotto è troppo grande per rappresentare, diciamo che l’operazione trabocca; il risultato è quindi un infinito di segno appropriato.

    In caso contrario, il prodotto viene arrotondato al valore più vicino nel set di valori scelto utilizzando la modalità round-to-closest IEEE 754. Il linguaggio di programmazione Java richiede il supporto di un underflow graduale come definito da IEEE 754 (§4.2.4).

    Nonostante il verificarsi di overflow, underflow o perdita di informazioni, la valutazione di un operatore di moltiplicazione * non genera mai un’eccezione run-time.