Preface
In C++, due to floating point numbers (float
/double
) storage method and accuracy issues are directly related to0
Make equality comparison (e.g.==
) may lead to unexpected results. The following is a detailed description from three aspects: principle, correct comparison method and code example:
1. The root cause of the problem of comparing floating point numbers with 0
-
The accuracy of floating point numbers
- Floating point numbers are stored in memory in scientific binary notation (according to IEEE 754 standard), and some decimal decimals cannot be expressed accurately.
- For example:
0.1
In binary, it is an infinite loop decimal, and there will be rounding errors when actually storing. - The tiny error accumulated during the calculation process may theoretically lead to
0
The value of is actually a very small non-zero value (e.g.1e-16
)。
-
A trap for direct comparison
double a = 0.1 + 0.1 + 0.1; // The theoretical value is 0.3, the actual value may be 0.300000000000000000004if (a == 0.3) { /* May not be true */ }
2. Correct comparison method
1. Compare whether the floating point number is 0
Use a very small threshold (epsilon
) Determine whether the floating point number is close to 0:
#include <cmath> // Use fabs bool isZero(double value, double epsilon = 1e-9) { return std::fabs(value) < epsilon; } // Example usagedouble x = 1e-10; if (isZero(x)) { std::cout << "x can be regarded as 0" << std::endl; }
2. Compare whether two floating point numbers are equal
Compare whether the difference between two floating point numbers is within the allowable range:
bool areEqual(double a, double b, double epsilon = 1e-9) { return std::fabs(a - b) < epsilon; } // Example usagedouble a = 0.1 + 0.1 + 0.1; double b = 0.3; if (areEqual(a, b)) { std::cout << "a and b are equal in the error range" << std::endl; }
3. Key points to note
-
Choose a reasonable epsilon
-
epsilon
The value of needs to be combined with specific scenarios:- Normal application:
1e-9
(For most cases). - Scientific calculations: smaller values may be required (e.g.
1e-15
)。
- Normal application:
- Avoid hard-code: use constants or pass
std::numeric_limits
Obtain machine accuracy:#include <limits> const double epsilon = std::numeric_limits<double>::epsilon();
-
-
Avoid the traps in comparison
-
Don't compare floating point numbers directly:
// Wrong practiceif (x == 0.0) { /* Unreliable */ }
-
Consider relative error:
For larger values, it may be necessary to compare the relative errors in combination (for example, to determine whether the two values are within the 1% error range).
-
Don't compare floating point numbers directly:
-
Processing of special values
-
NaN (non-numerical): Needed
std::isnan()
Test. -
Infinity:use
std::isinf()
Test.
double x = std::sqrt(-1.0); // Generate NaNif (std::isnan(x)) { std::cout << "x is non-numeric" << std::endl; }
-
NaN (non-numerical): Needed
4. Complete sample code
#include <iostream> #include <cmath> #include <limits> // Determine whether it is 0bool isZero(double value, double epsilon = 1e-9) { return std::fabs(value) < epsilon; } // Determine whether two floating point numbers are equalbool areEqual(double a, double b, double epsilon = 1e-9) { return std::fabs(a - b) < epsilon; } int main() { double a = 0.1 + 0.1 + 0.1; // The actual value is about 0.300000000000000000004 double b = 0.3; // Direct comparison failed if (a == b) { std::cout << "Direct comparison: equality" << std::endl; } else { std::cout << "Direct comparison: unequal" << std::endl; } //The error range is relatively successful if (areEqual(a, b)) { std::cout << "Error comparison: equality" << std::endl; } // Determine whether it is 0 double x = 1e-10; if (isZero(x)) { std::cout << "x can be regarded as 0" << std::endl; } return 0; }
5. Summary
operate | The correct way | Error Method |
---|---|---|
Determine whether the floating point number is 0 | fabs(val) < epsilon |
val == 0.0 |
Determine whether two floating point numbers are equal | fabs(a - b) < epsilon |
a == b |
Handle special values (NaN/Inf) |
std::isnan(val) / std::isinf(val)
|
Direct comparison |
Following the above method can avoid logical errors caused by floating point accuracy problems and ensure the robustness of the code.
This is the article about how to compare floating point numbers and double types in C++ with 0 values. For more related contents of comparison of floating point numbers, double and 0 values, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!