2013-08-08 20 views
11

Sto cercando di scoprire come rubino gestisce zero divisione. Ruby restituisce risultati diversi in base alla classe. Questo è quello che ho provatoCome fa il rubino a gestire la divisione zero?

0/0  # => ZeroDivisionError: divided by 0  
1/0  # => ZeroDivisionError: divided by 0 
1.0/0 # => Infinity 
0.0/0.0 # => NaN 

Che cosa sta succedendo qui? Non dovrei avere un ZeroDivisionError per tutti i casi di cui sopra?

Aggiornamento "Infinity" è un tipo di dati standard, quindi?

(1.0/0).class # => Float 
+4

I galleggianti non sono gli stessi di ints. Sembra che tu abbia già elencato i problemi. Cose come NaN e Infinity sono tipiche per i galleggianti. –

+0

@DaveNewton ma non vi è eccezione nel caso dei float, perché è così? – ZX12R

+0

Perché non si tratta di un'eccezione quando si ha a che fare con l'aritmetica in virgola mobile; c'è un valore ben definito ('Infinity' o' NaN'). Vedi https://en.wikipedia.org/wiki/IEEE_floating_point#Exception_handling dal link di Gene. –

risposta

10

Ruby traccia solo il IEEE 754 Floating Point Standard. Quella pagina di Wikipedia non è male a spiegare ciò che stai vedendo. Molte lingue moderne adottano lo stesso approccio.

Intuitivamente, il comportamento che si vede ha perfettamente senso. In generale,

1/<small number> = <big number> 

Pertanto nel limite,

1/0 -> Infinity and similarly -1/0 -> -Infinity 

Infinity è una costante compresa dal sottosistema virgola mobile. D'altra parte

0/<any non-zero> = 0 

Quindi abbiamo un conflitto su 0/0. Dovrebbe essere zero o infinito? La risposta standard IEEE è "Not a Number", lo NaN che stai vedendo, un'altra costante a virgola mobile.

Le costanti NaN e più o meno Infinity si propagano attraverso le espressioni in un modo che ha anche senso. Per esempio:

Infinity + <any (necessarly finite) number> = Infinity 

e

<any number> + NaN = NaN 

E cosa ancor più interessante:

1/Infinity = 0 

che si può provare da soli:

irb(main):005:0> 1.0/(1.0/0.0) 
=> 0.0 

In questo modo un calcolo a virgola mobile può continua anche quando ha overflow o diviso per zero e produce comunque una risposta ragionevolmente informativa (anche se dopo aver conosciuto bene lo standard, vedrai che affidarti alla risposta è di solito una cattiva idea).

Questo è lontano dall'unico comportamento fornito dallo standard. Altri possono essere selezionati Ma Ruby fa questo per te. Il file sorgente numeric.c, funzione Init_Numeric, imposta il processore host in modo che la divisione per zero propaga gli infiniti. Altre lingue potrebbero fare altre scelte, ad esempio per generare un'eccezione.

+7

Suggerirei di includere informazioni reali nelle risposte piuttosto che un semplice collegamento. –

+0

Um. Scusate. L'informazione è che tiene traccia dello standard IEEE 754. Ogni programmatore dovrebbe essere consapevole di questo standard in tutta la sua ampiezza. Se cito frammenti qui, il lettore perderà questa opportunità. – Gene

+4

Le risposte di solo collegamento non sono davvero ok, comunque. Non nascondersi dietro "devono leggere l'intera cosa per se stessi al fine di mostrare le due frasi necessarie per spiegare la vera domanda". Invece, evidenzia la necessità di capire oltre il livello di superficie, * e * rispondi alla domanda specifica. –

7

Il comportamento di punti galleggianti riflette lo standard IEEE 754:

  • operazione non valida (ad esempio, radice quadrata di un numero negativo) (restituisce QNAN di default).
  • Divisione per zero (un'operazione su operandi finiti fornisce un risultato infinito esatto, ad es. 1/0 o log (0)) (restituisce ± infinity per impostazione predefinita).

La decisione di attuare un errore di runtime per divisione intera per zero è comune in molti altri linguaggi così come Java, C++, Python. Python chiama in realtà l'errore ZeroDivisionError pure.

Vedere sawa's answer per i motivi di queste classificazioni e comportamenti.

4

Il punto è che un galleggiante ha un errore di arrotondamento. Un float 0.0 non esprime necessariamente zero esatto o 0.0 in senso matematico, ma è rappresentativo di tutti i numeri che verrebbero arrotondati a 0.0 data la precisione. La divisione per l'esatto 0 non è definita matematicamente, ma il divieto di divisione per 0.0 avrebbe il pericolo di restituire un errore nel caso in cui il divisore avesse un valore assoluto diverso da zero abbastanza piccolo da essere arrotondato a 0.0. Non si desidera che un programma restituisca improvvisamente un errore quando il valore assoluto del divisore è piccolo quando non è zero. In caso di float, è più sicuro che il sistema assegni un determinato numero alla divisione per 0.0 piuttosto che per impedirlo. Ma quel numero non può essere espresso in modo normale, quindi viene assegnato NaN o Infinito. Ciò che è fuorviante in questo è che l'Infinito non è l'infinito in senso matematico. Significa semplicemente "un numero più grande di qualsiasi altro numero che può essere espresso in questo sistema". Questo spiega il caso di:

1.0/0.0 # => Infinity 
0.0/0.0 # => NaN 

Quando un argomento di / è un galleggiante, rubino tipo-getta l'altra a galleggiare, così

1/0.0 
1.0/0 

sarebbe lo stesso come 1.0/0.0.

D'altra parte, il numero intero 0 non include un errore ed è lo zero esatto, quindi non esiste tale pericolo. Ha più senso sollevare un errore di divisione zero. Questo spiega

1/0 # => Error 
0/0 # => Error 
Problemi correlati