2009-06-24 10 views
13

È consigliabile utilizzare IEEE754 in virgola mobile NaN (non-un-numero) per valori che non sono definiti per motivi non matematici?È consigliabile utilizzare il NaN in virgola mobile IEEE754 per i valori non impostati?

Nel nostro caso non sono ancora impostati perché i valori non sono stati ricevuti da qualche altro dispositivo. Il contesto è un sistema embedded che utilizza valori REAL32 IEC1131. Modifica: Il linguaggio di programmazione è C, quindi molto probabilmente utilizzere NAN e isnanf (x), che provengono da C99. Anche se potremmo aver bisogno di alcune contorsioni extra per ottenere questi nel nostro livello di compatibilità del sistema operativo.

L'impostazione predefinita nei linguaggi di programmazione sembra essere quella di inizializzare le variabili in virgola mobile con zero positivo, la cui rappresentazione interna è tutti zero. Questo non è utilizzabile per noi, perché 0 è nell'intervallo di valori validi.

Sembra una soluzione pulita per utilizzare NaN, ma forse è più fastidioso di quanto valga e dovremmo scegliere qualche altro valore?

+0

Non so C, ma in .NET 1.1 prima che venissero fuori i tipi nullable, un sacco di persone usavano cose come il valore minimo (int.MinValue). Il problema con questo è che devi tenerlo in considerazione ovunque e assicurarti di non utilizzare mai MinValue. Forse qualcosa di simile esiste per C? – RichardOD

+1

Ho fatto una domanda simile (ma non uguale), forse le risposte possono aiutarti anche tu. http://stackoverflow.com/questions/787828/nan-as-a-special-argument – quinmars

risposta

10

Appena notato questa domanda.

Questo è uno degli usi dei NaN che il comitato IEEE 754 ha in mente (io ero un membro del comitato). Le regole di propagazione per i NaN in aritmetica rendono questo molto attraente, perché se si ottiene un risultato da una lunga sequenza di calcoli che coinvolgono alcuni dati inizializzati, non si confonderà il risultato con un risultato valido. Può anche fare il rintracciamento dei calcoli per scoprire dove si stanno utilizzando i dati inizializzati in modo molto più semplice.

Detto questo, ci sono alcune insidie ​​che non rientrano nel controllo del comitato 754: come altri hanno notato, non tutto l'hardware supporta i valori NaN alla velocità, il che può comportare rischi per le prestazioni. Fortunatamente, spesso non si eseguono molte operazioni sui dati inizializzati in un'impostazione critica per le prestazioni.

+0

Accettato perché in questo caso abbiamo usato NaN per undefined, anche se si è rivelato più un problema del previsto. Questo è stato principalmente dovuto al fatto che il supporto NaN nei nostri strumenti e sistemi era mancante o difettoso e abbiamo dovuto risolvere il problema. – starblue

3

Ho usato i NaN in situazioni simili proprio per questo: il solito valore di inizializzazione predefinito 0 è anche un valore valido. I NaN funzionano bene finora.

È una buona domanda, a proposito, perché il valore di inizializzazione predefinito è in genere (ad esempio, nei tipi primitivi Java) 0 e non in NaN. Non potrebbe anche essere 42 o qualsiasi altra cosa? Mi chiedo quale sia la logica degli zeri.

+1

Penso che la motivazione per l'utilizzo di 0 sia che la memoria sia inizializzata con zero byte indipendentemente dal tipo, ad esempio nel segmento BSS di C – starblue

+0

Sì, probabilmente è qualcosa del genere.Ma ora che i progettisti di linguaggio/compilatore hanno fatto lo sforzo di inizializzare la memoria, non sarebbe altrettanto facile inizializzarlo con qualsiasi valore arbitrario (diverso da zero)? Gli zeri sono solo alcuni bit tra gli altri :-) –

+2

@ mad-j: si desidera inizializzare tutta la memoria con lo stesso schema di bit. Quindi non poteva essere 42, perché di solito dovresti fare qualcosa di diverso per due pantaloncini adiacenti di quello che fai per un int. Questo lascia 0 e -1. Ma 0xffffffff non è -1 come float, quindi dovresti avere un'incoerenza lì. Non c'è molto in esso, ma penso che 0 sia probabilmente il migliore. Inoltre, alcuni hardware possono efficientemente 0 interi blocchi di memoria fisica in una volta, per quello che vale. –

0

Se il tuo bisogno di base è di avere un valore in virgola mobile che non rappresenta un numero che potrebbe essere stato ricevuto dal dispositivo, e se il dispositivo garantisce che non restituirà mai NaN, allora sembra ragionevole me.

Basta ricordare che a seconda dell'ambiente, probabilmente avete bisogno di un modo speciale di rilevare NaNs (non basta usare if (x == float.NaN) o qualunque sia il vostro equivalente.)

+0

Non credere a questa risposta. Tutto ciò che Jon Skeet deve fare è pensare alla variabile e si definirà. –

+0

Il valore è definito prima delle cose Skeet di un nome di variabile, giusto? – glasnt

4

NaNs sono una scelta ragionevole per un 'nessun valore' sentential (il linguaggio di programmazione D li utilizza per i valori non inizializzati, per esempio), ma perché ogni confronto che coinvolgono loro sarà falso, è possibile ottenere una qualche sorpresa:

  • if (result == DEFAULT_VALUE), non funzionerà come previsto se DEFAULT_VALUE è NaN, come ha detto Jon.

  • Possono anche causare problemi con il controllo di intervallo se non si fa attenzione. Si consideri la funzione:

 
bool isOutsideRange(double x, double minValue, double maxValue) 
{ 
    return x < minValue || x > maxValue; 
} 

Se x è NaN, questa funzione potrebbe segnalare erroneamente che x è compreso tra minValue e maxValue.

Se si desidera semplicemente un valore magico per gli utenti su cui eseguire il test, si consiglia l'infinito positivo o negativo anziché il NaN, in quanto non viene fornito con le stesse trap. Usa NaN quando lo desideri per la sua proprietà che qualsiasi operazione su un NaN produca un NaN: è utile quando non vuoi fare affidamento sui chiamanti che controllano il valore, per esempio.

[Modifica: Inizialmente sono riuscito a digitare "sopra tutti i confronti che li coinvolgono sarà vero" sopra, che non è quello che intendevo, ed è sbagliato, sono tutti falsi, a parte NaN!= NaN, che è vero]

+0

Quale lingua usa queste regole di confronto? Forse D lo fa. Ma almeno C e C++ non funzionano con NaN in questo modo. Tutti i confronti degli ordini saranno falsi. x == NaN è falso per ogni x, incluso NaN. –

+1

No, la funzione segnala solo che non è al di fuori dell'intervallo. Non è né interno né esterno, il che può davvero confondere quelli che usano i numeri in virgola mobile in modo ingenuo. – starblue

+0

@Igor: stiamo dicendo la stessa cosa qui. isOutsideRange restituirebbe false se x è NaN, il che implica che è all'interno dell'intervallo, che non è. – jskinner

1

I miei sentimenti sono che è un po 'hacky, ma almeno tutti gli altri numeri con cui fai operazioni con questo valore NaN danno come risultato NaN - quando vedi un NaN in una segnalazione di bug, almeno sai che tipo di errore stai cercando.

2

Stai attento con NaN ... possono diffondersi a macchia d'olio se non stai attento.

Sono un valore perfettamente valido per i float, ma qualsiasi assegnamento che li coinvolge eguaglierà anche NaN, quindi si propagano attraverso il codice. Questo è abbastanza buono come strumento di debug se si cattura, ma può anche essere un vero fastidio se si sta portando qualcosa da rilasciare e c'è un caso marginale da qualche parte.

D utilizza questo come motivazione per dare float NaN come predefinito. (Che non sono sicuro sono d'accordo.)

+9

Err ... Non è solo il punto dei NaN che si propagheranno? È molto meglio avere NaN come risultato, il che indica che c'è qualcosa di sbagliato, piuttosto che avere un numero innocente ma totalmente scorretto (che risulterebbe dall'uso accidentale di numeri inizializzati a zero). –

+1

Sì e no, perché quando si individua NaN solo guardando l'output o controllando esplicitamente NaN. La conseguenza di ciò è che gli errori possono essere rilevati molto più tardi di quanto si presentano. D'altra parte, se si utilizzano valori NULL (se possibile), si ottiene un errore NPE/segmentazione piuttosto veloce. Brutale, ma efficiente. –

+0

Se tutto quello che sai è che i NaN sono ovunque, non ti aiuta esattamente a scoprire da dove provengono. – corsiKa

3

Penso che sia una cattiva idea in generale. Una cosa da tenere a mente è che la maggior parte della CPU tratta Nan molto più lentamente del solito "float". Ed è difficile garantire che non avrai mai Nan nelle solite impostazioni. La mia esperienza nel calcolo numerico è che spesso porta più problemi di quanti ne valga.

La soluzione corretta è evitare di codificare "assenza di valore" nel float, ma di segnalarlo in un altro modo. Ciò non è sempre pratico, tuttavia, a seconda del codice base.

0

Questo mi sembra un buon uso per me. Vorrei averlo pensato ...

Certo, si suppone che si propagano come un virus, questo è il punto.

Penso che userò nan invece di uno degli infiniti. Potrebbe essere bello usare un nan di segnalazione e farlo causare un evento al primo utilizzo, ma a quel punto è troppo tardi dovrebbe diventare silenzioso al primo utilizzo.

0

L'utilizzo di NaN come valore predefinito è ragionevole.

Si noti che alcune espressioni, come (0.0/0.0), restituiscono NaN.