C++中double类型相等判断异常及循环未触发问题咨询
C++浮点数精度相关问题解答
代码示例
#include <iostream> #include <math.h> #include <vector> int main() { size_t N = 20; double from = 0.0; double to = 1.0; std::vector<double> xVec{}; double h = (to - from) / double(N); for (double x = from; x <= to; x += h) { // 未进入x == 1.0的迭代 xVec.push_back(x); std::cout << x << "\n"; } std::cout << "\n"; double x = 0.9; const std::vector<double>::iterator it = std::lower_bound(xVec.begin(), xVec.end(), x); std::cout << x << " " << *it << " " << (x == *it) << "\n"; // 显示0.9 != 0.9 }
运行输出
0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95 0.9 0.9 0
疑问1:为何循环条件x <= to无法进入x == 1.0的迭代?
这是浮点数的二进制表示精度限制导致的:
- 十进制的
0.05无法被二进制浮点数精确存储,它在二进制中是无限循环小数,实际存储的是一个近似值。 - 每次循环执行
x += h时,都会累积这个微小的误差,经过20次累加后,最终结果会略大于1.0(而非精确等于)。 - 当循环到
x = 0.95时,执行x += h后,x的实际值会比1.0大一点,此时x <= to(to是精确的1.0)的条件不成立,循环终止,因此不会进入x == 1.0的迭代。
疑问2:为何std::lower_bound返回的double值与直接赋值的0.9相等判断结果为false?
核心原因还是浮点数的近似存储特性:
- 向量中的
0.9是通过多次累加近似的0.05得到的,是多次误差累积后的近似结果。 - 直接赋值的
double x = 0.9,是将十进制0.9直接转换为二进制浮点数的近似值,这个值和累加得到的0.9在二进制存储上存在细微差异。 - 浮点数的
==操作是精确的二进制位比较,只要两个值的二进制表示有任何差异,结果就是false。
如果需要判断两个浮点数是否“实际相等”,应该通过比较它们的差值是否小于一个极小的阈值,示例代码如下:
#include <limits> // ... bool isEqual = std::abs(x - *it) < 10 * std::numeric_limits<double>::epsilon();
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

