C ++ doppia divisione per 0,0 rispetto DBL_MIN
-
04-10-2019 - |
Domanda
Quando trovare la radice quadrata inversa di un doppio, è meglio bloccare ingressi validi non positivi a 0,0 o MIN_DBL? (Nell'esempio qui sotto double b
può finire per essere negativo dovuto al punto di errori di arrotondamento e perché le leggi della fisica sono leggermente un po 'eluso nel gioco mobile.)
Sia divisione per 0,0 e MIN_DBL producono lo stesso risultato in gioco perché 1/0.0
e 1/DBL_MIN
sono effettivamente infinito. Il mio intuito dice MIN_DBL è la scelta migliore, ma ci sarebbe comunque per uso 0.0? Come forse sqrt(0.0)
, 1/0.0
e moltiplicazione per 1.#INF000000000000
eseguiti più velocemente perché sono casi speciali.
double b = 1 - v.length_squared()/(c*c);
#ifdef CLAMP_BY_0
if (b < 0.0) b = 0.0;
#endif
#ifdef CLAMP_BY_DBL_MIN
if (b <= 0.0) b = DBL_MIN;
#endif
double lorentz_factor = 1/sqrt(b);
doppia divisione in MSVC:
1/0.0 = 1.#INF000000000000 1/DBL_MIN = 4.4942328371557898e+307
Soluzione
Quando si tratta di matematica in virgola mobile, "infinito" e "in modo efficace l'infinito" sono molto diverse. Una volta che un numero smette di essere finito, tende a rimanere tale. Così, mentre il valore di lorentz_factor
è "efficace" lo stesso per entrambi i metodi, a seconda di come si utilizza questo valore, i calcoli successivi possono essere radicalmente diverso. sqrt(lorentz_factor)
per esempio resti infinito se si morsetto per 0, ma sarà effettivamente calcolato se si morsetto per alcuni molto molto piccolo numero.
Quindi la risposta dipenderà in larga misura ciò che si pensa di fare con quel valore una volta che hai bloccato esso.
Altri suggerimenti
Perché non basta INF
assegnare a lorentz_factor
direttamente, evitando sia la chiamata sqrt
e la divisione?
double lorentz_factor;
if (b <= 0.0)
lorentz_factor = std::numeric_limits<double>::infinity();
else
lorentz_factor = 1/sqrt(b);
- Avrai bisogno di
#include <limits>
per questo. - È inoltre possibile utilizzare
::max()
invece di::infinity()
, se è questo quello che vi serve.