【问题标题】:Strange multiplication result奇怪的乘法结果
【发布时间】:2014-08-17 10:21:53
【问题描述】:

在我的代码中,我在所有变量类型为 double[] 的 C++ 代码中进行了乘法运算

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 个处理器产生 1.66967e-13 作为 F1[1] 乘法的结果。

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

【问题讨论】:

  • MPI 提示竞争条件:数学几乎从来都不是错误。
  • 什么是 f1_rot[0] 和 f1_rot[1]/
  • 是的,我还要说你产生了一个竞争条件。也许您在显示的代码之前忘记了一些障碍(f1_rotxu 等。在执行乘法之前没有可靠地设置)。
  • @user3344003 Force Rot1 和 Force Rot2

标签: c++ multiplication openmpi double-precision


【解决方案1】:

您的问题是所谓的灾难性求和的明显结果: 我们知道,双精度浮点数可以处理大约 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,它对应于您在示例中给出的浮点数中的小数位数:(例如:-5.39155e-07 -3.66312e-07,每个尾数的精度为 6 位小数)。这意味着您在这里使用了单精度浮点数。

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

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

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

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

【讨论】:

  • 好的,我现在明白我是如何得到这些数字的了。然而,这意味着在移动到大量处理器时会损失精度?这是怎么发生的,可以解决吗?
  • 好像你在做矩阵产品。对于大矩阵,将两个以上的项相加。如果您对系数感兴趣,理论上,可以使用一些技术来减少信息的丢失:例如,分别将负数和正数从最小(绝对值)到最大相加。还有所谓的Kahan summation ... 可以更适应矩阵。无论如何,您不会手动执行此操作,某些库可以做到这一点。
  • >>> 一般来说,您不需要对矩阵的所有系数都具有很高的精度;实际上,矩阵是一组具有意义的许多值。当您注意到精度损失时,它不会涉及最大的系数,只有那些可以忽略不计的才会受到影响。但是,如果较小和较大系数之间的对比度很高,您可能会获得病态矩阵。
  • 为了提高数字的精度,必须有一些(符号)库做得很好。但是,您可能会注意到计算速度变慢。比如你可以试试GNU ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-21
  • 2014-02-23
相关资源
最近更新 更多