为什么我在 GPU 上有很大的精度错误?
Why do I have big precision errors on GPU?
我正在 GPU 上进行一系列计算,需要足够好的精度,但我得到的精度似乎比在 CPU.
上使用 float 时要低得多
对于初学者来说,当我在浮点缓冲区中加载 0.01
的值时,它会在着色器中加载为 0.009995
。这是为什么?我认为 0.01
是浮点向量范围内的值(使用可用于 Metal 的 simd
库)。
然后,当做这样一个简单的操作时,精度明显变差:
simd::float4 p = simd::float4 { -0.04, -0.07, 0, 1 };
simd::float4 v = myMatrix * p;
v *= 1.0 / v.w;
示例中的 p
是我在 CPU 测试中期望和使用的;在 GPU 上它被计算为 { -0.039978, -0.069946, 0.0, 1.0 }
,用一个整数减法和一个浮点数乘以已经错误的 0.009995
.
我期望从 v
得到的是 { -0.010627, 0.006991, -0.034100 }
(使用 CPU 上的 simd
库计算,精度已经比使用双精度更差,{ -0.010613, 0.006982, -0.034056 }
,但可以忍受)。
我得到的是 { -0.010483, 0.006405, -0.044067 }
。随着后续操作的进行,情况变得更糟,结果很快变得无法使用。
为什么即使使用相同的精度结果也如此不同,为什么没有加载浮点数据1:1?我尝试禁用 Metal 的 fast math 选项,但它没有改变任何东西。
浮点值不能有 0.01
,因为没有二进制表示。这就是使用 0.009995
的原因。我想 SO 已经有了关于二进制浮点数表示的很好的答案,所以你只需要搜索。
这里 good tool 用于检查浮点数在二进制中的样子。如果你输入 0.01
你会看到这个:
Decimal Representation: 0.01
Binary Representation: 00111100001000111101011100001010
After casting to double precision: 0.009999999776482582
唉,这不是精度问题,因为我设置测试的方式不正确,所以 GPU 没有使用我实际认为它使用的数字。
我正在 GPU 上进行一系列计算,需要足够好的精度,但我得到的精度似乎比在 CPU.
上使用 float 时要低得多对于初学者来说,当我在浮点缓冲区中加载 0.01
的值时,它会在着色器中加载为 0.009995
。这是为什么?我认为 0.01
是浮点向量范围内的值(使用可用于 Metal 的 simd
库)。
然后,当做这样一个简单的操作时,精度明显变差:
simd::float4 p = simd::float4 { -0.04, -0.07, 0, 1 };
simd::float4 v = myMatrix * p;
v *= 1.0 / v.w;
示例中的 p
是我在 CPU 测试中期望和使用的;在 GPU 上它被计算为 { -0.039978, -0.069946, 0.0, 1.0 }
,用一个整数减法和一个浮点数乘以已经错误的 0.009995
.
我期望从 v
得到的是 { -0.010627, 0.006991, -0.034100 }
(使用 CPU 上的 simd
库计算,精度已经比使用双精度更差,{ -0.010613, 0.006982, -0.034056 }
,但可以忍受)。
我得到的是 { -0.010483, 0.006405, -0.044067 }
。随着后续操作的进行,情况变得更糟,结果很快变得无法使用。
为什么即使使用相同的精度结果也如此不同,为什么没有加载浮点数据1:1?我尝试禁用 Metal 的 fast math 选项,但它没有改变任何东西。
浮点值不能有 0.01
,因为没有二进制表示。这就是使用 0.009995
的原因。我想 SO 已经有了关于二进制浮点数表示的很好的答案,所以你只需要搜索。
这里 good tool 用于检查浮点数在二进制中的样子。如果你输入 0.01
你会看到这个:
Decimal Representation: 0.01
Binary Representation: 00111100001000111101011100001010
After casting to double precision: 0.009999999776482582
唉,这不是精度问题,因为我设置测试的方式不正确,所以 GPU 没有使用我实际认为它使用的数字。