Sobes.tech
Junior

Kuidas kontrollida kahe ujukomaarvu (float) võrdust?

sobes.tech AI

Vastus AI-lt

Võrdlemine otse == operaatoriga ei ole soovitatav seetõttu, et arvutuste esitus ja ümardamine võivad põhjustada vigu. Selle asemel tuleks kontrollida, kas kahe numbri absoluutne erinevus on väikese künnise (epsilon) piires.

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

Stabiilsem lähenemine arvestab suhtelise veaga, eriti kui võrreldavad arvud on väga suured või väga väikesed:

#include <cmath>
#include <limits>

bool are_equal_robust(float a, float b, float epsilon = std::numeric_limits<float>::epsilon()) {
    // Võrdleme erinevust arvu mõõtmetega
    // Oluline on eraldi käsitleda nulli ja lõpmatust
    if (a == b) {
        return true; // Käsitleb juhtumeid a=b (sh lõpmatus ja NaN, kui need on omavahel võrdsed – mis ei kehti NaN-i puhul, kuid kehtib lõpmatuse puhul)
    }

    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; // Mõlemad arvud on lähedased nullile
    } else {
        return absolute_difference / max_abs < epsilon; // Suhtelise erinevuse võrdlus
    }
}

Epsilon valik sõltub nõutavast täpsusest ja võrreldavate väärtuste vahemikust. std::numeric_limits<float>::epsilon() esindab väikseimat arvu, mille puhul 1.0 + epsilon on erinev 1.0-st.

Oluline on meeles pidada, et NaN (Not a Number) võrdlus alati tagastab false, kaasa arvatud NaN võrdlus iseendaga (nan == nan on alati false). Kui on vaja NaN-i eraldi töödelda, tuleb see teha eraldi.