浮点精度可以依赖于线程吗?

时间:2010-05-17 09:28:58

标签: c# .net multithreading floating-accuracy

我在C#3.0中有一个基于struct的小型3D矢量类,它使用double作为基本单元。

一个例子:一个向量的y值是

-20.0 straight

我减去y值为

的向量
10.094999999999965

我期望的y值是

-30.094999999999963         (1)

相反,我得到

-30.094999313354492         (2)

当我在一个单独的线程中进行整个计算时,我得到(1)。调试器和VS快速监视器也会返回(1)。但是,当我在一个线程中运行几次迭代然后从另一个线程调用该函数时,结果是(2)。现在,调试器也返回(2)!

我们必须记住.NET JIT可能会将值写回内存(网站Jon Skeet),这会将精度从80位(FPU)降低到64位(双倍)。但是,(2)的准确性远远低于该值。

vector类看起来基本上就像这个

public struct Vector3d
{
  private readonly double _x, _y, _z;
  ...
  public static Vector3d operator -(Vector3d v1, Vector3d v2)
  {
      return new Vector3d(v1._x - v2._x, v1._y - v2._y, v1._z - v2._z);
  }  
}

计算就像这个

一样简单
Vector3d pos41 = pos4 - pos1;

1 个答案:

答案 0 :(得分:5)

是的,我相信结果可能与线程有关。

我的猜测是你在代码中的某个时刻使用DirectX - 它设置了FPU的精度,我相信它是基于每个线程设置的。

要解决此问题,请在致电CreateDevice时使用D3DCREATE_FPU_PRESERVE标记。请注意,这可能会对性能产生影响。托管等效项为CreateFlags.FpuPreserve

(请参阅this related question。我没有建议将此作为副本关闭,因为它们至少看起来表面上有点不同。两者都应该有帮助答案是可被发现的。)