【问题标题】:Numerical Problems with cancellation in C++C++ 中取消的数值问题
【发布时间】:2013-02-21 18:59:50
【问题描述】:

我在浮点运算中确实存在取消问题。我知道问题出在哪里,但我想不出一个有效的解决方案。

这是我的问题:我有一个 3D 粒子模拟,所以每个粒子都有 3 个坐标(x、y、z)。整个域被分成子单元。在某一时刻,我计算了粒子在某个时间步长所在的子单元格的 ID。这是一个简单的公式:

   int cellOffset_y = (pos[1] - y_min) / cellWidth_y;

pos[1] 是粒子的 x 坐标,y_min 是域的开始,cellWidth 是单元格的宽度。

这是我的问题:我有一个测试用例,在这种情况下粒子的坐标应该是 0。由于浮点不准确,它大约是 0。 -3e-18。当我使用这个公式时,-3e-18 由于取消而下降。现在最大的问题是,由于粒子位置为负,并且边界正好在 0,我得到的 cellID 与粒子实际所在的 cellID 不同。

那么有人知道如何解决这个问题吗?希望说明清楚

【问题讨论】:

  • 你不能用一个公差来比较吗? (例如 epsilon)。
  • 同样在你的片段中,cellOffset_y 是一个整数,e-18 将只是 0。
  • @111111: 我想是pos 那是-3e-18...
  • 是的,cellOffset_y 应该是一个 int,因为它是 y 方向上单元格的 ID。 pos[1] 在我的示例中是 -3e-18,是的
  • 使用近似坐标可以获得近似的单元格 ID,尤其是当粒子位于两个单元格之间的边界时。这在粒子方法中是完全正常的。我没有看到这里的问题(我自己做了很长一段时间的粒子模拟),我会责怪你的测试用例。

标签: c++ mpi numeric floating-accuracy cancellation


【解决方案1】:

基本上有两个选择(好吧,三个,如果你把“忍受这个问题”算作一个有效的选择!):

  1. 稍微移动网格中的边界,以允许一定程度的上游不准确。所以计算会变成(pos - y_min + k) / width,对于k的一些小值。

    当然,这并不能处理在另一个方向上发生的错误(即稍微太大的数字);事实上,这使情况变得更糟。但是没有通用的方法来解决这个问题;您的代码无法“知道” -3e-18 是正确的还是稍有错误!

  2. 修正上游计算。

【讨论】:

  • 1.有你提到的问题,它只会在一个方向上工作,上游计算基本上是一个给定的公式(我使用velocity-strömer-verlet算法)。第三种方法是在计算后检查边界是否正确,但这需要对每个粒子进行额外的 6 次检查,我对性能感兴趣......
  • @Chris:确实。所以这真的不是一个好的解决方案,除非你知道,例如,上游计算是有偏差的。
  • @Chris:当然,如果你有一些替代机制来验证正确性,那么你可以使用它(但大概这并不能告诉你在错误的情况下正确答案是什么,否则你'会首先使用这种机制吗?)。但在一般情况下,没有办法知道输入是错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多