奇怪的乘法结果

时间:2014-06-26 14:03:02

标签: c++ multiplication openmpi double-precision

在我的代码中,我在C ++代码中进行了这种乘法,所有变量类型都是double []

f1[0] = (f1_rot[0] * xu[0]) + (f1_rot[1] * yu[0]); 
f1[1] = (f1_rot[0] * xu[1]) + (f1_rot[1] * yu[1]); 
f1[2] = (f1_rot[0] * xu[2]) + (f1_rot[1] * yu[2]); 

f2[0] = (f2_rot[0] * xu[0]) + (f2_rot[1] * yu[0]); 
f2[1] = (f2_rot[0] * xu[1]) + (f2_rot[1] * yu[1]);
f2[2] = (f2_rot[0] * xu[2]) + (f2_rot[1] * yu[2]);

对应这些值

Force Rot1 : -5.39155e-07, -3.66312e-07
Force Rot2 : 4.04383e-07, -1.51852e-08

xu: 0.786857, 0.561981, 0.255018
yu: 0.534605, -0.82715, 0.173264

F1: -6.2007e-07, -4.61782e-16, -2.00963e-07
F2: 3.10073e-07, 2.39816e-07, 1.00494e-07

这种乘法特别产生了错误的值-4.61782e-16而不是1.04745e-13

f1[1] = (f1_rot[0] * xu[1]) + (f1_rot[1] * yu[1]);  

我亲自验证了计算器上的其他乘法,它们似乎都产生了正确的值。

这是一个开放的mpi编译代码,上面的结果用于运行单个处理器,运行多个处理器时有不同的值,例如40个处理器因F1 [1]乘法而产生1.66967e-13。

这是某种mpi错误吗?还是类型精度问题?为什么它适用于其他乘法?

1 个答案:

答案 0 :(得分:5)

您的问题是所谓的灾难性总结的明显结果: 我们知道,双精度浮点数可以处理大约16位有效小数的数字。

f1[1] = (f1_rot[0] * xu[1]) + (f1_rot[1] * yu[1])
      = -3.0299486605499998e-07 + 3.0299497080000003e-07
      = 1.0474500005332475e-13

这是我们使用您在示例中给出的数字获得的。 请注意(-7) - (-13) = 6,它对应于您在示例中给出的float中的小数位数:(例如:-5.39155e-07 -3.66312e-07,每个尾数的精度为6位小数)。这意味着你在这里使用了单精度浮点数。

我相信在您的计算中,您的数字的精确度会更高,这就是您找到更精确结果的原因。

无论如何,如果你使用单精度浮动,你不能期望更好的精度。使用双精度,您可以找到最多16的精度。您不应该相信两个数字之间的差异,除非它大于尾数:

  • 简单的精确浮动:(a-b)/ b> = ~1e-7
  • 双精度浮子:(a-b)/ b> = ~4e-16

有关详细信息,请参阅these examples ...table in this article ...