Java Language Gli operatori aritmetici (+, -, *, /,%)

Esempio

Il linguaggio Java fornisce 7 operatori che eseguono l'aritmetica su valori interi e in virgola mobile.

  • Ci sono due operatori + :
    • L'operatore di aggiunta binaria aggiunge un numero a un altro. (Esiste anche un operatore binario + che esegue la concatenazione di stringhe, come descritto in un esempio separato).
    • L'operatore unario plus non fa nulla oltre all'attivazione della promozione numerica (vedi sotto)
  • Ci sono due - operatori:
    • L'operatore di sottrazione binaria sottrae un numero da un altro.
    • L'operatore unario meno equivale a sottrarre il suo operando da zero.
  • L'operatore di moltiplicazione binario (*) moltiplica un numero per un altro.
  • L'operatore di divisione binaria (/) divide un numero per un altro.
  • L'operatore del resto 1 binario (%) calcola il resto quando un numero viene diviso per un altro.

1. Questo è spesso erroneamente definito come l'operatore "modulo". "Remainder" è il termine utilizzato da JLS. "Modulo" e "resto" non sono la stessa cosa.

Operand e tipi di risultato e promozione numerica

Gli operatori richiedono operandi numerici e producono risultati numerici. I tipi di operando possono essere qualsiasi tipo di carattere numerico primitivo (es. byte , short , char , int , long , float o double ) o qualsiasi tipo di wrapper numerico definito in java.lang ; es. ( Byte , Character , Short , Integer , Long , Float o Double .

Il tipo di risultato è determinato in base ai tipi dell'operando o degli operandi, come segue:

  • Se uno degli operandi è double o Double , il tipo di risultato è double .
  • Altrimenti, se uno degli operandi è float o Float , il tipo di risultato è float .
  • Altrimenti, se uno degli operandi è long o Long , il tipo di risultato è long .
  • Altrimenti, il tipo di risultato è int . Questo copre byte , short e char operandi così come `int.

Il tipo di risultato dell'operazione determina come viene eseguita l'operazione aritmetica e come vengono gestiti gli operandi

  • Se il tipo di risultato è double , gli operandi vengono promossi a double e l'operazione viene eseguita utilizzando l'aritmetica in virgola mobile IEE 754 a 64 bit (binario a precisione doppia).
  • Se il tipo di risultato è float , gli operandi vengono promossi in float e l'operazione viene eseguita utilizzando l'aritmetica in virgola mobile IEE 754 a 32 bit (binario a precisione singola).
  • Se il tipo di risultato è long , gli operandi vengono promossi a long e l'operazione viene eseguita utilizzando l'aritmetica di numeri interi binari a due complementi con segno a 64 bit.
  • Se il tipo di risultato è int , gli operandi vengono promossi a int e l'operazione viene eseguita utilizzando l'aritmetica di numeri interi binari a due complementi con segno a 32 bit.

La promozione viene eseguita in due fasi:

  • Se il tipo di operando è un tipo di wrapper, il valore dell'operando è non inserito in un valore del tipo primitivo corrispondente.
  • Se necessario, il tipo primitivo viene promosso al tipo richiesto:
    • La promozione di interi per int o long è senza perdite.
    • La promozione del float da double è senza perdite.
    • La promozione di un intero con un valore in virgola mobile può portare a una perdita di precisione. La conversione viene eseguita utilizzando la semantica IEE 768 "round-to-nearest".

Il significato della divisione

L'operatore / divide l'operando di sinistra n (il dividendo ) e l'operando di destra d (il divisore ) e produce il risultato q (il quoziente ).

La divisione intera Java si arrotonda verso lo zero. La sezione 15.17.2 di JLS specifica il comportamento della divisione in intero Java come segue:

Il quoziente prodotto per gli operatori n e d è un valore intero q cui grandezza è la più grande possibile mentre soddisfa |d ⋅ q| ≤ |n| . Inoltre, q è positivo quando |n| ≥ |d| e n e d hanno lo stesso segno, ma q è negativo quando |n| ≥ |d| e n e d hanno segni opposti.

Ci sono un paio di casi speciali:

  • Se n è MIN_VALUE e il divisore è -1, si verifica un overflow di numero intero e il risultato è MIN_VALUE . Nessuna eccezione è lanciata in questo caso.
  • Se d è 0, viene lanciata l'opzione ArithmeticException.

La divisione Java floating point ha altri casi da considerare. Tuttavia l'idea di base è che il risultato q è il valore più vicino alla soddisfazione d . q = n .

La divisione in virgola mobile non genererà mai un'eccezione. Invece, le operazioni che dividono per zero risultano in valori INF e NaN; vedi sotto.

Il significato di resto

A differenza di C e C ++, l'operatore rimanente in Java funziona con operazioni sia a interi che a virgola mobile.

Per i casi interi, il risultato di a % b è definito come il numero r tale che (a / b) * b + r è uguale a a , dove / , * e + sono gli operatori di numero intero Java appropriati. Questo vale in tutti i casi tranne quando b è zero. In quel caso, il resto risulta in ArithmeticException .

Dalla definizione sopra riportata risulta che a % b può essere negativa solo se a è negativa, ed è positiva solo se a è positiva. Inoltre, la grandezza di a % b è sempre inferiore alla grandezza di b .

L'operazione di resto del punto mobile è una generalizzazione del caso intero. Il risultato di a % b è il resto r è definito dalla relazione matematica r = a - (b ⋅ q) dove:

  • q è un numero intero,
  • è negativo solo se a / b è negativo e solo se a / b è positivo, e
  • la sua grandezza è la più ampia possibile senza superare la grandezza del vero quoziente matematico di a e b .

Il resto in virgola mobile può produrre valori INF e NaN in casi limite come quando b è zero; vedi sotto. Non genererà un'eccezione.

Nota importante:

Il risultato di un'operazione remainder a virgola mobile come calcolata da % non è uguale a quella prodotta dall'operazione resto definita da IEEE 754. Il resto IEEE 754 può essere calcolato utilizzando il metodo di libreria Math.IEEEremainder .

Overflow intero

I valori interi Java 32 e 64 bit sono firmati e utilizzano la rappresentazione binaria a due complementi. Ad esempio, l'intervallo di numeri rappresentabili come (32 bit) int -2 31 a +2 31 - 1.

Quando si aggiunge, si sottraggono o più due numeri interi a N bit (N == 32 o 64), il risultato dell'operazione potrebbe essere troppo grande per rappresentare un numero intero N bit. In questo caso, l'operazione porta a un overflow di numeri interi e il risultato può essere calcolato come segue:

  • L'operazione matematica viene eseguita per fornire una rappresentazione intermedia del complemento a due dell'intero numero. Questa rappresentazione sarà più grande di N bit.
  • Come risultato, vengono utilizzati i 32 o 64 bit inferiori della rappresentazione intermedia.

È necessario notare che l'overflow dei numeri interi non comporta eccezioni in nessuna circostanza.

Valori INF e NAN a virgola mobile

Java utilizza le rappresentazioni in virgola mobile IEE 754 per float e double . Queste rappresentazioni hanno alcuni valori speciali per rappresentare valori che non rientrano nel dominio dei numeri reali:

  • I valori "infinito" o INF indicano numeri troppo grandi. Il valore +INF indica numeri troppo grandi e positivi. Il valore -INF denota numeri troppo grandi e negativi.
  • Il "indefinito" / "non un numero" o NaN denotano valori derivanti da operazioni prive di significato.

I valori INF sono generati da operazioni mobili che causano un overflow, o dalla divisione per zero.

I valori NaN vengono prodotti dividendo zero per zero o calcolando zero resto zero.

Sorprendentemente, è possibile eseguire operazioni aritmetiche utilizzando gli operandi INF e NaN senza attivare eccezioni. Per esempio:

  • Aggiungere + INF e un valore finito dà + INF.
  • Aggiungere + INF e + INF dà + INF.
  • Aggiungere + INF e -INF dà NaN.
  • Dividere per INF fornisce +0.0 o -0.0.
  • Tutte le operazioni con uno o più operandi NaN danno NaN.

Per i dettagli completi, fare riferimento alle sottosezioni rilevanti di JLS 15 . Si noti che questo è in gran parte "accademico". Per i calcoli tipici, un INF o NaN significa che qualcosa è andato storto; ad esempio, hai dati di input incompleti o errati o il calcolo è stato programmato in modo errato.