2012-04-24 136 views
11

我有是找到在一个图上的路径,并输出该累积重量的程序。图形中的所有边都有一个浮点形式的单个权重为0到100,最多有2个小数位。0 + 0 + 0 ... + 0!= 0

在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除了将它们添加到总数之外,没有其他操作在其上执行。

+19

你能构建一个最小的测试用例吗? – 2012-04-24 18:22:33

+0

@OliCharlesworth这是我一直在努力做到的,迄今没有运气。相关代码的数量太多,但我会继续尝试在较小范围内重现该错误。我希望在这背后会有明显的推理。 – 2012-04-24 18:24:28

+0

我会建议你看看机器epsilon的定义。这似乎是什么导致你的错误在这里。 – andre 2012-04-24 18:28:15

回答

11

因为它是一个IEEE浮点号码,它不完全等于零。

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

+3

但问题是:为什么? (如为什么它不是零)?但是,这还不能回答,因为我们需要从OP中看到一个测试用例。 – 2012-04-24 18:29:47

+0

我在本科数值分析课程中研究了很多浮点问题,但我从未发现0 + 0应该是0以外的任何情况。我从来没有做过任何其他操作。 – 2012-04-24 18:31:54

+0

http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm为什么0不是0?我认为“零”部分表示0是0,并且在IEEE 754规则中有精确表示。 – 2012-04-24 18:31:57

3

这可能是因为您的包含“0.0F”值花车实际上不是0.0F(位表示00000000),但计算结果为约0.0个非常非常小的数目。由于IEEE754规范定义的浮点表示,如果你有,例如,一个非常小尾数和0指数,虽然它并不等于绝对的0时,将全面为0。但是,如果你添加这些数字加在一起足够的方式次数,这个非常小的数额将累积成最终将变为非零的值。

下面是一个例子情况下,它给出了0的错觉是非零:

float f = 0.1f/1000000000; 
printf("%f, %08x\n", f, *(unsigned int *)&f); 
float f2 = f * 10000; 
printf("%f, %08x\n", f2, *(unsigned int *)&f2); 

如果你指定文字到你的变量和添加他们,但是,它有可能,要么编译器不在存储器中将0转换为0x0。如果是,这仍然发生,那么它也有可能是你的CPU硬件有关于转0到非零这样做,可能会通过他们的验证工作尖叫ALU操作时的错误。

然而,这是好事,记住,IEEE浮点只是一个近似值,和任何特定的浮点值不是一个确切的表示。所以任何浮点运算都会有一定的错误。

+0

不,这不像我的情况。我永远不会分裂。我只将0和0.0f分配给变量,然后添加它们。 – 2012-04-24 18:40:30

+0

我给出了一个可能导致错觉的例子。当然,许多不同的情况可能会导致类似的情况。 – 2012-04-24 18:41:52

+0

对,我从来没有想过,添加常量0可能会导致这种情况。 – 2012-04-24 18:42:32

5

以最多2个小数位的浮点形式出现。

有没有这样的事情,作为一个浮动与至多2位小数。浮点几乎总是表示为二进制浮点数(小数二进制尾数和整数指数)。如此多的(大多数)小数点后两位数字不能完全表示。

例如,0.20f可以看作是一个天真圆形部分,但

printf("%.40f\n", 0.20f); 

会打印:0.2000000029802322387695312500000000000000。

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

当然,对于大多数实际应用来说,其差异可以忽略不计。但是如果你做了一些计算,你最终可能会增加舍入误差并使其可见,特别是大约为0.

+0

我知道这是非零值,但我的问题是在处理只有0时出现的。但是,对于大量零点稍微偏离的情况,或许正如另一个答案中指出的那样引起了问题。 – 2012-04-24 18:35:40

+0

你怎么知道你正在处理0?他们是编译常量吗?从文件读取? – rodrigo 2012-04-24 18:37:03

+0

我尝试使用常量并从文件中读取数据。 – 2012-04-24 18:37:45

相关问题