Ecco come ho iniziato ad esaminare per l'uguaglianza, senza un "fattore di correzione":
if (
// Test 1: Very cheap, but can result in false negatives
a==b ||
// Test 2: More expensive, but comprehensive
std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon())
std::cout << "The numbers are equal\n";
Spiegazione
Il primo test è un semplice confronto. Naturalmente sappiamo tutti che confrontare i valori a doppia precisione può far sì che vengano considerati ineguali, anche quando sono logicamente equivalenti.
Un valore in virgola mobile a doppia precisione può contenere le quindici cifre più significative di un numero (in realtà ≈15.955 cifre). Pertanto, vogliamo chiamare due valori uguali se (approssimativamente) corrispondono alle loro prime quindici cifre. Per dirla in un altro modo, vogliamo chiamarli uguali se si trovano all'interno di un epsilon in scala l'uno dell'altro. Questo è esattamente ciò che calcola il secondo test.
È possibile scegliere di aggiungere più margine di manovra rispetto a un singolo epsilon ridimensionato, a causa di errori di virgola mobile più significativi che si insinuano come risultato del calcolo iterativo. Per fare questo, aggiungere un fattore di errore sul lato destro del confronto del secondo prova:
double error_factor=2.0;
if (a==b ||
std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*
error_factor)
std::cout << "The numbers are equal\n";
non posso dare un valore fisso per la error_factor
, poiché dipenderà dalla quantità di errore che si insinua nella vostra calcoli. Tuttavia, con alcuni test dovresti essere in grado di trovare un valore ragionevole adatto alla tua applicazione. Tieni presente che l'aggiunta di un fattore di errore (arbitrario) basato sulla sola speculazione ti riporterà nel territorio del fattore fudge.
Sommario
Puoi avvolgere il seguente test in un (n inline) Funzione:
inline bool logically_equal(double a, double b, double error_factor=1.0)
{
return a==b ||
std::abs(a-b)<std::abs(std::min(a,b))*std::numeric_limits<double>::epsilon()*
error_factor;
}
Gli odori fanno i compiti, quindi per favore aggiungi il tag * compiti a casa * se è il caso. –
Divertente quanto lontano può viaggiare quell'odore ... –
@ user484955: Sai veramente cosa significa "while (a, b! = '|')"? –