0 + 0 + 0 ... + 0!= 0

Aus*_*ley 11 c++ floating-point

我有一个程序,它在图表中查找路径并输出累计权重.图中的所有边都具有0到100的单个权重,其形式为浮点数,最多2位小数.

在Windows/Visual Studio 2010上,对于由0权重的边组成的特定路径,它输出正确的总权重0.但是在Linux/GCC上,程序说该路径的权重为2.35503e-38.我有很多关于浮动引起的疯狂错误的经验,但是0 + 0什么时候会等于0以外的任何东西?

我能想到的唯一一件事是导致这个问题是程序确实将一些权重视为整数,并使用隐式强制将它们添加到总数中.但是0 + 0.0f仍然等于0.0f!作为一个快速修复,我将总数降低到0,当时小于0.00001,这足以满足我的需求.但是什么vodoo导致了这个?

注意:我100%确信图中没有任何权重超出我提到的范围,并且此特定路径中的所有权重都为0.

编辑:详细说明,我已经尝试从文件中读取权重并在代码中手动设置它们等于0.0f除了将它们添加到总数之外,没有对它们执行任何其他操作.

duf*_*ymo 11

因为它是IEEE浮点数,并且它不完全等于零.

http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm

  • @DavidTitarenco我认为你的评论可能是事实,但是dyffymo的答案太过一般了. (4认同)
  • 但问题是:为什么?(因为,为什么它不是零?)然而,这是不可能回答(还),因为我们需要从OP看到一个测试用例. (3认同)
  • 我相信编译器 - 如果它说0 + 0 + 0!= 0,那么其中一个零不是. (3认同)

rod*_*igo 5

[...]以最多2位小数的浮点数形式.

没有最多2位小数的浮点数.浮点数几乎总是表示为二进制浮点数(分数二进制尾数和整数指数).很多(大多数)带有2位小数的数字无法准确表示.

例如,0.20f可能看起来像一个无辜的圆形部分,但是

printf("%.40f\n", 0.20f);
Run Code Online (Sandbox Code Playgroud)

将打印:0.2000000029802322387695312500000000000000.

看,它没有2位小数,它有26个!!!

当然,对于大多数实际应用来说,差异可以忽略不计.但是如果你进行一些计算,最终可能会增加舍入误差并使其可见,尤其是在0左右.