Compararea valorilor double: toleranța în C++
Înțelege de ce unele calcule reale nu dau egalitate exactă. Alege toleranța după cerință și scară, fără să înlocuiești toate comparațiile cu aceeași constantă.
În acest material
Valorile de tip double sunt reprezentări finite ale numerelor reale. Unele fracții zecimale nu au reprezentare binară finită, așa că sunt stocate aproximativ. Două calcule care sunt egale în matematică pot ajunge la valori stocate foarte apropiate, dar nu identice.
Nu toate egalitățile sunt greșite
Dacă ai copiat exact aceeași valoare finită într-o altă variabilă, egalitatea poate fi verificată direct. Problema apare când compari rezultate obținute prin calcule care acumulează rotunjiri. Regula „nu folosi niciodată == cu double” este prea generală și ascunde întrebarea importantă: ce înseamnă egal în cerința ta?
Pentru măsurători sau rezultate aproximative, poți considera două valori suficient de apropiate dacă diferența absolută |a-b| este sub o toleranță declarată. Aceasta este o regulă a modelului problemei, nu egalitate matematică exactă.
Scara numerelor contează
O diferență de 0.001 poate fi mare când valorile sunt în jurul lui 0.002 și neglijabilă când sunt în jurul unui miliard. O toleranță absolută fixează o distanță pe axa numerelor. O toleranță relativă raportează diferența la mărimea valorilor comparate.
În unele aplicații se combină o limită absolută cu una relativă, de exemplu prin compararea diferenței cu maximul dintre o toleranță absolută și o toleranță relativă înmulțită cu scara valorilor. Aproape de zero, componenta absolută evită împărțirea la o scară nulă sau extrem de mică.
O diferență absolută de 0.001 este mare față de 0.001, dar mică față de 1000000. Toleranța trebuie raportată la mărimea valorilor și la cerință.Mărește schema ↗
Nu alege automat 10 la minus 9
Toleranța trebuie legată de precizia datelor, numărul operațiilor și condiția din enunț. Dacă evaluatorul precizează o eroare acceptată, urmărește exact acea regulă. Dacă problema cere calcule întregi exacte, trecerea la double cu o toleranță inventată poate transforma o soluție corectă într-una fragilă.
Un exemplu simplu: pentru a=1.0000 și b=1.0004, diferența este aproximativ 0.0004. O regulă cu toleranță absolută 0.001 le acceptă drept apropiate; una cu 0.0001 nu. Niciuna nu este universal corectă fără cerința aplicației.
Verifică și operațiile, nu doar comparația finală
O formulă care scade numere foarte apropiate sau adună valori pe scări foarte diferite poate amplifica pierderea de precizie. Schimbarea comparației finale nu repară automat o formulă instabilă. Pentru început, separă eroarea de reprezentare de o eroare logică în expresie.
Continuă cu tipurile numerice, funcțiile matematice și operatorii.
Întrebări frecvente
De ce două calcule cu double pot da rezultate ușor diferite?
Multe fracții zecimale sunt reprezentate aproximativ în binar, iar operațiile pot acumula rotunjiri. Egalitatea matematică nu implică automat reprezentări identice după trasee diferite de calcul.
Ce valoare epsilon trebuie folosită la compararea numerelor reale?
Nu există o valoare universală. Alege toleranța după precizia cerută și scara valorilor. Pentru unele probleme este potrivită o combinație de eroare absolută și relativă.
Este întotdeauna greșit să folosesc == pentru double?
Nu. De exemplu, egalitatea dintre aceeași valoare finită și copia ei poate fi verificată direct. Toleranța este necesară când cerința urmărește apropierea rezultatelor afectate de rotunjire.