Come forzo 0.0 / 0.0 a restituire zero, invece di NaN in MIPSPro compilatore C?
Domanda
Come afferma domanda, sto usando il compilatore C MIPSPRo, e ho un operazione che tornerà NaN per alcune serie di dati in cui sia il numeratore che denom sono pari a zero. Come faccio a evitare che ciò accada?
Soluzione
Su sistemi SGI con il compilatore MIPSPro, è possibile impostare la gestione di varie eccezioni in virgola mobile con precisione utilizzando le strutture in sigfpe.h
. Come accade, la divisione per zero zero è uno dei casi:
#include <stdio.h>
#include <sigfpe.h>
int main (void) {
float x = 0.0f;
(void) printf("default %f / %f = %f\n", x, x, (x / x));
invalidop_results_[_ZERO_DIV_ZERO] = _ZERO;
handle_sigfpes(_ON, _EN_INVALID, 0, 0, 0);
(void) printf("handled %f / %f = %f\n", x, x, (x / x));
return 0;
}
In uso:
arkku@seven:~/test$ cc -version
MIPSpro Compilers: Version 7.3.1.3m
arkku@seven:~/test$ cc -o sigfpe sigfpe.c -lfpe
arkku@seven:~/test$ ./sigfpe
default 0.000000 / 0.000000 = nan0x7ffffe00
handled 0.000000 / 0.000000 = 0.000000
Come si può vedere, fissando il risultato _ZERO_DIV_ZERO
cambia l'esito della stessa divisione. Allo stesso modo è possibile gestire divisione regolare per zero (per esempio, se non si desidera l'infinito come il risultato).
Naturalmente, niente di tutto questo è di serie; sarebbe più portatile per controllare NaN dopo ogni divisione e ancora meglio per controllare zeri prima. C99 offre alcuni controllo sull'ambiente in virgola mobile in fenv.h
, ma non credo niente di adatto per questo è disponibile. In ogni caso il mio vecchio MIPSPro non supporta C99.
Altri suggerimenti
Usa un clausola if? Anche io sono curioso di sapere perchè ci si vuole ignorare questa impossibilità matematica. Sei sicuro che il vostro ingresso non è sbagliato / senza senso in questo caso?
Se non ti dispiace l'introduzione di un piccolo errore, è possibile aggiungere un valore piccolo al denominatore, supponendo che si sta facendo aritmetica in virgola mobile. a quanto pare ha alcuni piccoli valori definiti:
DBL_MIN è il più piccolo doppio
DBL_EPSILON è il più piccolo doppio S.T. x + DBL_EPSILON! = x
Quindi vorrei provare
#include <float.h>
#define EPS DBL_MIN
double divModified(double num, double denom) {
return num / (denom + EPS);
}
IEEE 754 (le specifiche per la virgola mobile) dice che 0.0 / 0.0 è non un numero, cioè NaN
. Se si vuole che sia qualcos'altro, di gran lunga l'approccio migliore è quello di rilevare quando gli operandi sono entrambi pari a zero in una clausola if
e restituire il valore che si preferisce dare. Forse in questo modo:
#define WonkyDiv(a,b) ((a)==0.0&&(b)==0.0 ? 0.0 : (a)/(b))
float wonkyResult = WonkyDiv(numerator, denominator);