Se si sta cercando un valore che sarebbe propagato mediante operazioni aritmetiche, NaN
è ancora disponibile con l'opzione -ffast-math
. Il problema sta da qualche altra parte. Con -ffast-math
alcune operazioni possono essere rimosse dal calcolo a causa dell'ottimizzazione, e quindi non c'è modo di garantire NaN
o qualsiasi altro valore si propagherebbe.
Ad esempio, il seguente, con -ffast-math
set, causerà difficile scrivere 0.0
in n
e non v'è alcun valore speciale per n
che proteggerebbe da esso.
float n = NAN;
n *= 0.0;
Una cosa si può fare, è quello di utilizzare -fno-finite-math-only -ftrapping-math
con -ffast-math
come ha detto Shafik Yaghmour. E l'altro è, se ci sono solo pochi punti in cui ci si aspetta un valore negativo, è possibile verificarlo da solo mettendo i test esattamente in quei punti.
L'ultima opzione che posso pensare, se davvero hai bisogno dell'ottimizzazione, è iniettare manualmente i valori NaN
(e forse inf
) nel calcolo e controllare per quanto tempo viene propagato. Quindi, in quei luoghi in cui si interrompe la propagazione, verificare l'occorrenza di NaN
(inf
). - Questo è un metodo non sicuro, in quanto non ne sono sicuro al cento per cento, è possibile che lo -ffast-math
implichi il flusso condizionale delle operazioni. Se è possibile, c'è una possibilità significativa, questa soluzione non sarà valida. Quindi è rischioso e se scelto richiede test molto pesanti che coprano tutti i rami del calcolo.
Normalmente sarei piuttosto contrario all'ultima soluzione, ma in realtà c'è una possibilità, NaN
(inf
) i valori verranno propagati attraverso l'intero calcolo o quasi interi, in modo da poter fornire le prestazioni che stai cercando. Quindi potresti voler correre il rischio.
Controllo della NaN
con -ffast-math
si può fare, come diceva Shafik Yaghmour, con
inline int isnan(float f)
{
union { float f; uint32_t x; } u = { f };
return (u.x << 1) > 0xff000000u;
}
e per double
con
inline int isnan(double d)
{
union { double d; uint64_t x; } u = { d };
return (u.x << 1) > 0xff70000000000000ull;
}
Controllo per inf
sarebbe
inline int isinf(float f)
{
union { float f; uint32_t x; } u = { f };
return (u.x << 1) == 0xff000000u;
}
inline int isinf(double d)
{
union { double d; uint64_t x; } u = { d };
return (u.x << 1) == 0xff70000000000000ull;
}
È inoltre possibile unire isnan
e isinf
.
Questa discussione potrebbe essere utile [Mingw32 std :: isnan con -ffast-math] (http://stackoverflow.com/questions/7263404/mingw32-stdisnan-with-ffast-math) –
@ShafikYaghmour Grazie, quella discussione è utile – stgtscc
Esiste anche l'opzione di usare '-fno-finite-math-only -ftrapping-math' http://lua-users.org/lists/lua-l/2009-04/msg00091.html –