Come si controllano i valori infiniti e indeterminati in C ++?
-
03-07-2019 - |
Domanda
Nei miei programmi l'infinito di solito sorge quando un valore è diviso per zero. Divento indeterminato quando divido zero per zero. Come controllate i valori infiniti e indeterminati in C ++?
In C ++, l'infinito è rappresentato da 1. # INF. Indeterminato è rappresentato da -1. # IND. Il problema è come verificare se una variabile è infinita o indeterminata. Controllare l'infinito è relativamente semplice: trovi la definizione di infinito nel tuo particolare C ++. Nel mio caso (VS2003), è std :: numeric_limits :: infinity (). Devi includere & Quot; limits & Quot; per usarlo. Puoi assegnare questo valore infinito a una variabile e confrontarlo con un valore per verificare se quel valore è infinito.
Indeterminato è un po 'complicato, perché non è possibile confrontare un valore indeterminato con un altro valore. Qualsiasi confronto restituisce false. È possibile utilizzare questa proprietà per rilevare un valore indeterminato confrontandolo con se stesso. Supponiamo che tu abbia una doppia variabile chiamata aVal. In condizioni normali, aVal! = AVal restituisce false. Ma se il valore è indeterminato, aIndVal! = AIndVal restituisce true. Questa strana situazione non è presente per valori infiniti, ovvero aInfVal! = AInfVal restituisce sempre false.
Ecco due funzioni che possono essere utilizzate per verificare valori indeterminati e infiniti:
#include "limits.h"
#include "math.h"
bool isIndeterminate(const double pV)
{
return (pV != pV);
}
bool isInfinite(const double pV)
{
return (fabs(pV) == std::numeric_limits::infinity())
}
Esistono modi migliori per questi controlli, mi manca qualcosa?
Soluzione
Per Visual Studio userei _isnan
e _finite
, o forse < a href = "http://msdn.microsoft.com/en-us/library/aa246882(VS.60).aspx" rel = "noreferrer"> _fpclass
.
Ma se si ha accesso a una libreria e compilatore standard in grado di supportare C ++ 11, è possibile utilizzare std::isnan
e std::isinf
.
Altri suggerimenti
Sebbene C ++ 03 non fornisca isnan di C99 e isinf macro , C ++ 11 standardizza fornendoli come funzioni . Se puoi usare C ++ 11, invece del rigoroso C ++ 03, queste sarebbero opzioni più pulite, evitando le macro, compilatore integrato e funzioni dipendenti dalla piattaforma.
C ++ 11 std::isfinite
restituisce true
per tutti i valori tranne inf
e nan
; quindi !isfinite
dovrebbe verificare la presenza di valori infiniti e indeterminati in un colpo solo.
Sebbene non sia strettamente parte di C ++ 03, se il compilatore fornisce alcune delle nuove funzionalità C99 dello standard < math.h > file di intestazione, quindi potresti avere accesso ai seguenti " macro simili a funzioni " ;: isfinite
, isinf
, isnan
. In tal caso, questi sarebbero il modo più semplice e sicuro per eseguire questi controlli.
Puoi anche usarli come una soluzione rigorosa per soli C ++. In realtà non offrono più della soluzione del PO, tranne una maggiore sicurezza attraverso l'uso di tratti di tipo e forse il più piccolo aumento di velocità nel caso di is_inf
.
template <bool> struct static_assert;
template <> struct static_assert<true> { };
template<typename T>
inline bool is_NaN(T const& x) {
static_cast<void>(sizeof(static_assert<std::numeric_limits<T>::has_quiet_NaN>));
return std::numeric_limits<T>::has_quiet_NaN and (x != x);
}
template <typename T>
inline bool is_inf(T const& x) {
static_cast<void>(sizeof(static_assert<std::numeric_limits<T>::has_infinity>));
return x == std::numeric_limits<T>::infinity() or x == -std::numeric_limits<T>::infinity();
}
(attenzione agli autocostruiti static_assert
)
C'è isfinite
da C99 o POSIX o qualcosa che penso.
Un modo hacker per farlo è testare x-x == 0
; se x
è infinito o NaN, quindi x-x
è NaN, quindi il confronto fallisce, mentre se 0
è finito, <=> è <=> e il confronto ha esito positivo. Ti consiglio di usare <=>, o di impacchettare questo test in una funzione / macro chiamata qualcosa come <=> in modo da poter sbarazzarti di tutto quando sarà il momento.
if (x!=x) ... then x is nan
if (x>0 && x/x != x/x) ... then x is +inf
if (x<0 && x/x != x/x) ... then x is -inf
questo potrebbe anche funzionare (ma implica call to exp () e test di uguaglianza dei doppi):
if (exp(-x)==0.) ... then x is inf
if (exp(x)==0.) ... then x is -inf