Sobes.tech
Junior

Come verificare l'uguaglianza di due numeri in virgola mobile (float)?

sobes.tech AI

Risposta dell'AI

Non è consigliabile confrontare direttamente con l'operatore == a causa delle peculiarità della rappresentazione e dell'arrotondamento. Invece, si dovrebbe verificare se il valore assoluto della differenza tra i numeri è entro una piccola soglia (epsilon).

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

Un approccio più robusto considera l'errore relativo, specialmente quando si confrontano numeri molto grandi o molto piccoli:

#include <cmath>
#include <limits>

bool are_equal_robust(float a, float b, float epsilon = std::numeric_limits<float>::epsilon()) {
    // Confronta la differenza considerando la scala dei numeri
    // È importante gestire separatamente i casi con zero e infinito
    if (a == b) {
        return true; // Gestisce i casi in cui a=b (inclusi infinito e NaN se sono uguali tra loro – cosa non vera per NaN, ma sì per infinito)
    }

    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; // Entrambi i numeri sono vicini a zero
    } else {
        return absolute_difference / max_abs < epsilon; // Confronto della differenza relativa
    }
}

La scelta di epsilon dipende dalla precisione richiesta e dall'intervallo di valori da confrontare. std::numeric_limits<float>::epsilon() rappresenta il più piccolo numero tale che 1.0 + epsilon è diverso da 1.0.

È importante ricordare che il confronto con NaN (Not a Number) restituisce sempre false, incluso il confronto di NaN con se stesso (nan == nan è sempre false). Se si necessita di gestire NaN, questo deve essere fatto separatamente.