You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

浮点数与整数相等性疑问:为何计算显示1却判定不等?

问题分析:浮点数直接比较的精度陷阱

你碰到的这个问题,本质是浮点数运算的精度误差在搞鬼!

明明用cout输出距离看起来是1,但用==和1比较却返回0(也就是false),这是因为powsqrt这类浮点函数计算出来的结果,并不是严格等于1.0的——它可能是一个非常接近1的数值,比如0.9999999999999999或者1.0000000000000002。当cout输出时,默认的显示精度会把这些近似值四舍五入成1给你看,但内存里实际存储的数值和1.0还是有那么一丢丢差距,直接用==比较自然就不相等了。

拿你的例子来说,计算(0,0,0)到(0,0,1)的距离,理论值是1,但浮点数运算中,哪怕是pow(1,2)这种看似简单的操作,都可能因为二进制浮点数的表示限制产生微小的舍入误差,再经过sqrt计算后,最终结果就和精确的1.0差了一点点。

那该怎么解决呢?给你两个常用的方案:

  • 用epsilon(极小阈值)做近似比较:不要直接判断相等,而是判断两个数的差值是否小于一个极小的数,比如C++标准库提供的std::numeric_limits<double>::epsilon(),或者自定义一个比如1e-9的阈值。示例代码:
#include <cmath>
#include <limits>
#include <iostream>

struct vertice { 
    double x, y, z; 
    vertice(double x, double y, double z) : x(x), y(y), z(z) {} 
}; 

void cartDistance(const vertice * a, const vertice * b) { 
    double dx = b->x - a->x;
    double dy = b->y - a->y;
    double dz = b->z - a->z;
    double dist = sqrt(dx*dx + dy*dy + dz*dz);
    
    std::cout << "dist: " << dist << std::endl;
    // 用epsilon做近似比较
    bool isEqual = std::abs(dist - 1.0) < std::numeric_limits<double>::epsilon();
    std::cout << "dist check: " << isEqual << std::endl;
} 

int main() { 
    cartDistance(new vertice(0, 0, 0), new vertice(0, 0, 1)); 
    system("pause"); 
    return 0; 
}
  • 避免不必要的浮点运算:比如这个场景里,你可以先计算距离的平方(dx*dx + dy*dy + dz*dz),直接比较平方值是否接近1.0,这样还能省去sqrt的计算,减少精度损失的可能:
double dist_sq = dx*dx + dy*dy + dz*dz;
bool isEqual = std::abs(dist_sq - 1.0) < std::numeric_limits<double>::epsilon();

最后再提醒一句:浮点数的本质是用有限的二进制位近似表示实数,几乎所有浮点运算都会有微小的精度损失。所以永远不要直接用==!=比较两个浮点数是否相等,除非你能确定它们是完全相同的数值(比如直接赋值的常量)。

内容的提问来源于stack exchange,提问作者Jonathan Woollett-light

火山引擎 最新活动