Sobes.tech
Junior

Cum să verifici egalitatea a două numere în virgulă mobilă (float)?

sobes.tech AI

Răspuns de la AI

Nu este recomandat să comparați direct cu operatorul == din cauza particularităților reprezentării și rotunjirii. În schimb, trebuie verificat dacă valoarea absolută a diferenței dintre numere se află în limitele mici (epsilon).

bool are_equal(float a, float b, float epsilon = 0.00001f) {
    return std::abs(a - b) < epsilon;
}

O abordare mai robustă ia în considerare eroarea relativă, mai ales când comparăm numere foarte mari sau foarte mici:

#include <cmath>
#include <limits>

bool are_equal_robust(float a, float b, float epsilon = std::numeric_limits<float>::epsilon()) {
    // Compară diferența ținând cont de scala numerelor
    // Este important să tratăm separat cazurile cu zero și infinit
    if (a == b) {
        return true; // Trata cazurile în care a=b (inclusiv infinit și NaN dacă sunt egale între ele – ceea ce nu este cazul pentru NaN, dar pentru infinit da)
    }

    float absolute_difference = std::abs(a - b);
    float max_abs = std::max(std::abs(a), std::abs(b));

    if (max_abs < epsilon) {
        return absolute_difference < epsilon; // Ambele numere sunt apropiate de zero
    } else {
        return absolute_difference / max_abs < epsilon; // Compararea diferenței relative
    }
}

Alegerea epsilon depinde de precizia necesară și de intervalul de valori comparate. std::numeric_limits<float>::epsilon() reprezintă cel mai mic număr astfel încât 1.0 + epsilon diferă de 1.0.

Este important să rețineți că comparația cu NaN (Not a Number) returnează întotdeauna false, inclusiv comparația nan == nan. Dacă este necesar să tratați NaN, acest lucru trebuie făcut separat.