2012-10-18 19 views
49

La seguente istruzione getta come ovvio lo java.lang.ArithmeticException:/by zero.Perché la divisione per zero con numeri in virgola mobile (o precisione doppia) non genera java.lang.ArithmeticException:/per zero in Java

System.out.println(0/0); 

perché il letterale 0 è considerato un int letterale e dividere per zero non è consentito in aritmetica intera.

Il seguente caso però non gettare alcuna eccezione come java.lang.ArithmeticException:/by zero.

int a = 0; 
double b = 6.199; 
System.out.println((b/a)); 

Visualizza Infinity.

La seguente istruzione produce NaN (Not a Number) senza eccezioni.

System.out.println(0D/0); //or 0.0/0, or 0.0/0.0 or 0/0.0 - floating point arithmetic. 

In questo caso, entrambi gli operandi sono considerati raddoppiati.


Allo stesso modo, le seguenti affermazioni non gettare alcuna eccezione.

double div1 = 0D/0; //or 0D/0D 
double div2 = 0/0D; //or 0D/0D 

System.out.printf("div1 = %s : div2 = %s%n", div1, div2); 
System.out.printf("div1 == div2 : %b%n", div1 == div2); 
System.out.printf("div1 == div1 : %b%n", div1 == div1); 
System.out.printf("div2 == div2 : %b%n", div2 == div2); 
System.out.printf("Double.NaN == Double.NaN : %b%n", Double.NaN == Double.NaN); 
System.out.printf("Float.NaN == Float.NaN : %b%n", Float.NaN == Float.NaN); 

Producono il seguente output.

div1 = NaN : div2 = NaN 
div1 == div2 : false 
div1 == div1 : false 
div2 == div2 : false 
Double.NaN == Double.NaN : false 
Float.NaN == Float.NaN : false 

Tutti ritorno false. Perché questa operazione (divisione per zero) permessi a virgola mobile o numeri di doppia precisione?


proposito, posso capire che i numeri in virgola mobile (numeri di doppia precisione) hanno i valori che rappresentano infinito positivo, infinito negativo, non un numero (NaN) ...

+0

Nel primo caso, dal momento che si sta utilizzando un int, la promozione potrebbe comportare qualcosa come 0.00..001, o qualcosa di simile a Double.MIN_VALUE, che fornirebbe un numero enorme se si divide nulla da essa . – broncoAbierto

+1

@Tiny: Trasforma la tua domanda in giro: perché '1/0' lancia un'eccezione invece di restituire 'Infinito'? La risposta è che un intero in complemento a due (che è ciò che Java 'int' è) non ha alcun bit disponibile per memorizzare valori speciali come' Infinity' o 'NaN', quindi dal momento che il risultato non è rappresentabile nel tipo desiderato , un'eccezione deve essere lanciata. I numeri in virgola mobile non hanno questo problema (esiste un pattern di bit disponibile per 'Infinity'), e quindi non è necessaria alcuna eccezione. –

risposta

47

In breve, questo è il modo in cui è specificato nello standard IEEE-754, che è ciò su cui sono basate le Floating-Point Operations di Java.

Why doesn't division by zero (or overflow, or underflow) stop the program or trigger an error? Why does a standard on numbers include "not-a-number" (NaN)?

Il modello 754 incoraggia programmi robusti. È destinato non solo agli analisti numerici ma anche agli utenti di fogli di calcolo, ai sistemi di database o persino alle caffettiere. Le regole di propagazione per i NaN e gli infiniti consentono di escludere le eccezioni irrilevanti. Allo stesso modo, l'underflow graduale mantiene le proprietà di errore nell'intervallo di precisione.

Quando situazioni eccezionali richiedono attenzione, possono essere esaminate immediatamente tramite trap o in un momento opportuno tramite flag di stato. Le trappole possono essere utilizzate per fermare un programma, ma le situazioni irrecuperabili sono estremamente rare. Basta interrompere un programma non è un'opzione per i sistemi embedded o gli agenti di rete. Più spesso, i trap registrano le informazioni diagnostiche o sostituiscono i risultati validi.

Le bandiere offrono sia il flusso di controllo prevedibile che la velocità. Il loro uso richiede che il programmatore sia a conoscenza di condizioni eccezionali, ma l'appiccicosità della bandiera consente ai programmatori di posticipare la gestione di condizioni eccezionali fino al momento necessario.

8

l'infinito e oltre

class DoubleDivision { 

    public static void main(String[] args) { 
     System.out.println(5.0/0.0); 
    } 
} 

Il codice precedente e i frammenti citati danno infinity.

Perché Java utilizza Double s per rappresentare i decimali. Il binario non può rappresentare completamente un numero, può solo rappresentare un'approssimazione e, quindi, nemmeno il doppio di Java.

Immagina un numero incredibilmente vicino allo zero. Se conosci il calcolo, immagina un limite a zero. La variabile si avvicinerebbe a zero ad una distanza immaginabile minuscola, ma mai uguale esattamente. Puoi immaginarlo, giusto? Bene, supponiamo che quel numero abbia bisogno di tanta precisione da rappresentare per Java, si arrende e lo chiama 0.0 perché non ha una buona alternativa. Ecco cosa sta succedendo qui. Qualsiasi numero normale diviso da un numero super vicino a zero è fondamentalmente, infinito. Provalo: 5/(10^-100).

Vedere anche la sezione: speciale Floating-Point Valori a Math Errors per ulteriori informazioni :)

questione connessa: why does 1/0 give error but 1.0/0/0 give inf

UPDATE: INT non ha un infinito e NaN valore nel set, mentre float ha un valore infinito e NaN. (Secondo gli standard IEEE 754 seguito da java)

+5

_Binary non può rappresentare completamente un numero, può solo rappresentare un'approssimazione e quindi nemmeno la doppia di Java. Uno zero è completamente rappresentabile nella notazione a virgola mobile (qualsiasi?). –

+1

Per float/double secondo IEEE 754, esiste un +0 e un -0, usiamo 0.0 per rappresentare, ma in realtà questa è la semplificazione/approssimazione di '1/+ - infinito' che, come tutti sappiamo, non è' 0' ma si avvicina a '0'. è per questo che ho detto che 0 non è completamente rappresentabile. Immagino che una buona discussione ne stia uscendo. :-) –

+0

Il punto nel mio commento è che mentre la divisione per zero potrebbe non essere ben definita (da una rigorosa vista matematica), e alcune frazioni potrebbero essere impossibili da rappresentare, che potrebbe essere il caso di javas double ... ma zero _is_ defined e 0.0 == 0 come ci si aspetta che sia. Quindi il problema è la divisione, non lo zero. Non ti ho votato a morte, lo ha fatto qualcun altro. –

2

Java segue lo standard IEEE 754 che definisce i valori da restituire di default nel caso di una divisione per zero. http://en.wikipedia.org/wiki/IEEE_754#Exception_handling

divisione per zero (un'operazione operandi finiti dà un risultato esatto infinito, ad esempio, 1/0 o log (0)) (restituisce ± infinito di default).

5

Quando c'è una divisione per zero, il computer non può creare una rappresentazione del risultato come un numero. Il computer deve segnalare che il risultato non è un numero.

Per virgola mobile valori che può produrre un valore speciale sentinella non-a-numero, perché ci sono alcuni 32 bit (per float) e 64 bit (per double) sequenze di bit che non rappresentano un numero e quindi può essere interpretato come non-un-numero (NaN).

Per valori interi che utilizzano lo schema comune a due complementi (come richiesto da Java), tutti i modelli a 32 bit (per long) bit rappresentano un numero. Quindi il computer non può segnalare il problema usando una sentinella. Deve segnalare il problema "fuori dalla banda" in qualche modo. Lanciare un'eccezione è il metodo fuori banda scelto per Java.

14

È così perché è così che lo ha definito IEEE 754.

La divisione di un punto fluttuante 0,0 produce NaN o +/- Inf, a seconda che il numeratore sia 0 o meno.

divisione per un numero intero 0 non è coperto da IEEE 754, e genera un'eccezione - non c'è altro modo di indicare l'errore perché un int non può rappresentare NaN o Inf.

La generazione di un'eccezione è simile al (software) INT generato da una divisione per zero su microprocessori x86.

0
import java.util.Scanner; 

public class Division { 

    public static void main(String[] args) { 
     int a, b; 
     float result; 

     Scanner input = new Scanner(System.in); 
     System.out.println("Enter value for a : "); 
     a = input.nextInt(); 

     System.out.println("Enter value for b : "); 
     b = input.nextInt(); 

     try { 
      /* here we used "if clause" because result will be in float 
      note: Here result is in float, so JVM Cant Catch Exception. 
      if we Try to Divide with Zero with Float Values It gives Output as 
      Divided by Zero is Infinity */ 
      if (b != 0) { 
       result = (float) a/b; 
       System.out.println("Result of " + a + " divided by " + b + " is : " + result); 
      } else // here result will be in integer so Jvm can easily Catch The Exception 
      { 
       result = a/b; 
      } 
     } catch (ArithmeticException e) { 
      System.out.println("Sorry Division By Zero Is Not Possible"); 
     } 
    } 
} 

/* Ouput : 
Enter value for a :2 
Enter value for b : 7 
Result of 2 divided by 7 is : 0.2857143 */ 

/* Ouput : 
Enter value for a : 16 
Enter value for b : 0 
Sorry Division By Zero Is Not Possible */ 
+0

Mentre questo blocco di codice può rispondere alla domanda, sarebbe meglio se tu potessi fornire qualche spiegazione per ** perché ** lo fa. – DavidPostill

+0

qui abbiamo usato "if clause" perché il risultato sarà in float nota: Qui il risultato è in virgola mobile, quindi JVM Cant Catch Exception.if che proviamo a dividere con Zero con valori Float Dà Output come Divided da Zero è Infinity – sandeep16

Problemi correlati