2014-02-14 17 views
1

我正在使用NS-3(用C++编写)来模拟网络环境。比较NS-3中的两个双精度值时奇怪的数学错误C++

我正在使用其flowmonitor类来记录无线链接的性能指标。

我正在收集的一件事是当前和以前的数据包延迟或“抖动”之间的时间差异。

为了得到这个,我将一个数据包延迟的时间值(转换为双变量)减去前一个数值。

0.0159051 - 0.0158002 = 0.0001049

然而,经过一段时间的数学似乎行事很奇怪,如:

0.0159003 - 0.0158007 = 9.95972e-05

时答案显然应该是0.0000996

为了进一步阐述,我最初使用diff函数来找出差异。

template <typename T1, typename T2> 
double diff(const T1& lhs, const T2& rhs) 
{ 
    std::cout << lhs << " - " << rhs << std::endl; 
    return lhs - rhs; 
} 

但是,由于我发现了错误,我尝试了直接减法,但是我得到了同样的错误。

+2

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – knivil

回答

6

浮点格式使用尾数和指数的二进制表示形式,它不能精确地表示每个十进制(十进制)的数字分数,并且它的精度是有限的,所以一定要检查双精度格式是否可以精确地表示您的值。更多关于双格式here on wikipedia。关于堆栈溢出浮点精度的问题还有更多的问题,请检查this one和其他相关的问题。

有一些后果:

  1. 你不能指望你会得到你想要的数字
  2. 你不能简单地比较数字相等,(1.0+2.0)==3.0可以工作的精确值,但任何更复杂的分数计算与分数不能相等...
  3. 浮点数的精度是有限的,当你将许多数相加或相乘在一起,尤其是在不同的指数下,你将累积计算中的大误差(见Kahan summation algorithm
3

实数从+无穷延伸到无穷大,数字之间的间隙极小。这是不可能的在有限存储中表示所有实数。

为了解决这个问题,计算机存储了数字的大小(作为指数)和有效数字(尾数)的数量。这类似于写一个数字作为1.043×10^-5。

由于存储是不准确的,你会得到舍入误差和这些舍入误差有时可能显著。这确实意味着你无法在计算机上比较两个实数。充其量,你可以说他们的谎言比给定的宽容更接近。

为了说明这一点,以1.000除以3,然后乘以3,您应该返回1.000,但自1.000/3 = 0。333到3位小数,如果结果是0.999,不要感到惊讶。 (电脑使用二进制(基2),所以这可能会有不同的工作,但这一点仍然存在)