Domanda

È una buona idea usare IEEE754 in virgola mobile NaN (non un numero) per valori che non sono definiti per ragioni non matematiche?

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

L'impostazione predefinita nei linguaggi di programmazione sembra essere l'inizializzazione delle variabili in virgola mobile con zero positivo, la cui rappresentazione interna è tutta a zero. Questo non è utilizzabile per noi, perché 0 è compreso nell'intervallo di valori validi.

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

È stato utile?

Soluzione

Ho appena notato questa domanda.

Questo è uno degli usi delle NaN che il comitato IEEE 754 ha in mente (ero un membro del comitato). Le regole di propagazione per NaN in aritmetica lo rendono molto interessante, 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 rendere la traccia indietro attraverso i tuoi calcoli per trovare dove stai utilizzando i dati inizializzati molto più semplice.

Detto questo, ci sono alcune insidie ??che sono al di fuori del 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 ambiente critico per le prestazioni.

Altri suggerimenti

I NaN sono una scelta ragionevole per una frase "senza valore" (il linguaggio di programmazione D li usa per valori non inizializzati, per esempio), ma poiché qualsiasi confronto che li coinvolge sarà falso, puoi ottenere alcune sorprese:

  • if (risultato == DEFAULT_VALUE) , non funzionerà come previsto se DEFAULT_VALUE è NaN, come menzionato da Jon.

  • Possono anche causare problemi con il controllo della portata se non stai attento. Considera la funzione:

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

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

Se vuoi solo un valore magico per cui gli utenti testano, raccomanderei l'infinito positivo o negativo invece di NaN, poiché non viene fornito con le stesse trappole. Usa NaN quando lo desideri per la sua proprietà che qualsiasi operazione su un NaN dia come risultato un NaN: è utile quando non vuoi fare affidamento sui chiamanti che controllano il valore, ad esempio.

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

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

È una buona domanda, tra l'altro, perché il valore di inizializzazione predefinito è solitamente (ad esempio, nei tipi primitivi Java) 0 e non NaN. Non potrebbe anche essere 42 o altro? Mi chiedo quale sia la logica degli zeri.

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". galleggiante. Ed è difficile garantire che non avrai mai Nan nelle normali impostazioni. La mia esperienza nel calcolo numerico è che spesso porta più problemi di quanti ne valga la pena.

La soluzione giusta è quella di evitare la codifica "assenza di valore" nel galleggiante, ma per segnalarlo in un altro modo. Questo non è sempre pratico, tuttavia, a seconda della base di codice.

Fai attenzione ai NaN ... possono diffondersi come un incendio se non stai attento.

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

D usa questo come logica per dare NaN ai float come predefinito. (Che non sono sicuro di essere d'accordo.)

I miei sentimenti sono che è un po 'confuso, ma almeno tutti gli altri numeri che 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 sei caccia.

Se la tua necessità di base è avere un valore in virgola mobile che non rappresenti alcun numero che potrebbe essere stato ricevuto dal dispositivo, e se il dispositivo garantisce che non restituirà mai NaN, allora mi sembra ragionevole.

Ricorda solo che, a seconda del tuo ambiente, probabilmente avrai bisogno di un modo speciale di rilevare NaN (non usare if (x == float.NaN) o qualunque sia il tuo equivalente.)

Questo suona per me come un buon uso. Vorrei averci pensato ...

Certo, dovrebbero propagarsi come un virus, questo è il punto.

Penso che userei nan invece di uno degli infiniti. Potrebbe essere bello usare un nan di segnalazione e causare un evento al primo utilizzo, ma ormai è troppo tardi dovrebbe essere silenzioso al primo utilizzo.

L'uso di NaN come valore predefinito è ragionevole.

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top