浮点精度可以依赖于线程吗?
我在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;
是的,我相信结果可能是线程依赖的。
我的猜测是你在代码中的某个时刻使用DirectX – 并且它设置了FPU的精度,我相信它是基于每个线程设置的。
要解决此问题,请在调用CreateDevice
时使用D3DCREATE_FPU_PRESERVE标志。 请注意,这可能会对性能产生影响。 托管等效项是CreateFlags.FpuPreserve
。
(看到这个相关的问题 。我没有建议将这个作为副本关闭,因为它们表面上至少看起来有点不同。两者都应该有助于答案可被发现。)