Divisione per zero in Java: eccezione, infinito o non è un numero

1. Panoramica

La divisione per zero è un'operazione che non ha alcun significato nell'aritmetica ordinaria ed è, quindi, indefinita. In programmazione, tuttavia, mentre è spesso associato a un errore, non è sempre così .

In questo articolo vedremo cosa succede quando si verifica una divisione per zero in un programma Java.

Secondo le specifiche Java dell'operazione di divisione, possiamo identificare due diversi casi di divisione per zero: numeri interi e numeri in virgola mobile.

2. Numeri interi

In primo luogo, per i numeri interi, le cose sono piuttosto semplici. La divisione di un numero intero per zero risulterà in un'eccezione aritmetica :

assertThrows(ArithmeticException.class, () -> { int result = 12 / 0; });
assertThrows(ArithmeticException.class, () -> { int result = 0 / 0; });

3. Tipi in virgola mobile

Tuttavia, quando si tratta di numeri in virgola mobile , non verrà generata un'eccezione :

assertDoesNotThrow(() -> { float result = 12f / 0; });

Per gestire casi come questi, Java utilizza alcuni valori numerici speciali che possono rappresentare i risultati di tale operazione: NaN , POSITIVE_INFINITY e NEGATIVE_INFINITY.

3.1. NaN

Iniziamo dividendo i valori zero in virgola mobile per zero :

assertEquals(Float.NaN, 0f / 0); assertEquals(Double.NaN, 0d / 0);

Il risultato in questi casi è NaN (non un numero).

3.2. Infinito

Successivamente, dividiamo alcuni valori diversi da zero per zero :

assertEquals(Float.POSITIVE_INFINITY, 12f / 0); assertEquals(Double.POSITIVE_INFINITY, 12d / 0); assertEquals(Float.NEGATIVE_INFINITY, -12f / 0); assertEquals(Double.NEGATIVE_INFINITY, -12d / 0);

Come possiamo vedere, il risultato è INFINITO, con il segno dipendente dal segno degli operandi.

Inoltre, possiamo anche utilizzare il concetto di zero negativo per arrivare a NEGATIVE_INFINITY :

assertEquals(Float.NEGATIVE_INFINITY, 12f / -0f); assertEquals(Double.NEGATIVE_INFINITY, 12f / -0f);

3.3. Rappresentazione della memoria

Quindi, perché la divisione di numeri interi per zero genera un'eccezione, mentre la divisione in virgola mobile per zero non lo fa?

Diamo un'occhiata a questo da una prospettiva di rappresentazione della memoria. Per gli interi, non esiste uno schema di bit che possa essere utilizzato per memorizzare il risultato di tale operazione, mentre i numeri in virgola mobile hanno valori come NaN o INFINITY da utilizzare in casi come questi.

Consideriamo ora la rappresentazione binaria di un float come S EEEEEEE E FFFFFFF FFFFFFFF FFFFFFFF con un bit (S) per il segno, 8 bit (E) per l'esponente e il resto (F) per la mantissa.

In ciascuno dei tre valori NaN , POSITIVE_INFINITY e NEGATIVE_INFINITY, tutti i bit nella parte esponente sono impostati su 1.

INFINITY ha i bit di mantissa tutti impostati su 0, mentre NaN ha una mantissa diversa da zero:

assertEquals(Float.POSITIVE_INFINITY, Float.intBitsToFloat(0b01111111100000000000000000000000)); assertEquals(Float.NEGATIVE_INFINITY, Float.intBitsToFloat(0b11111111100000000000000000000000)); assertEquals(Float.NaN, Float.intBitsToFloat(0b11111111100000010000000000000000)); assertEquals(Float.NaN, Float.intBitsToFloat(0b11111111100000011000000000100000));

4. Riepilogo

Per riassumere, in questo articolo abbiamo visto come funziona la divisione per zero in Java.

Valori come INFINITY e NaN sono disponibili per i numeri in virgola mobile ma non per i numeri interi . Di conseguenza, la divisione di un numero intero per zero provocherà un'eccezione. Tuttavia, per un float o double , Java consente l'operazione.

Il codice completo è disponibile su GitHub.