大浮点数的 OpenCL 缩减结果错误
OpenCL reduction result wrong with large floats
我使用 AMD's two-stage reduction example 使用浮点精度计算从 0 到 65 536 的所有数字的总和。不幸的是,结果不正确。但是,当我修改我的代码,以便计算 65 536 个较小数字(例如 1)的总和时,结果是正确的。
我在代码中找不到任何错误。由于 float 类型,我是否有可能得到错误的结果?如果是这种情况,解决问题的最佳方法是什么?
这是使用有限精度 CPU 或 GPU 对浮点数求和的 "side effect"。准确性取决于算法和值求和的顺序。背后的理论和实践在 Nicholas J, Higham 的论文中解释
浮点求和的精度
解决方法是使用更智能的算法,例如 Kahan 求和算法
https://en.wikipedia.org/wiki/Kahan_summation_algorithm
海厄姆论文也有一些替代方案。
这个问题说明了基准测试的本质,基准测试的第一条规则是获得
正确答案,使用真实数据!
您的内核或主机应用程序的编码可能没有错误。问题出在单精度浮点数上。
正确的和是:65537 * 32768 = 2147516416,用二进制表示需要 31 位 (10000000000000001000000000000000)。 32 位浮点数最多只能精确保存 2^24 的整数。
"Any integer with absolute value less than [2^24] can be exactly represented in the single precision format"
"Floating Point" article, wikipedia
这就是当总和小于或等于 2^24 时得到正确总和的原因。如果您使用单精度进行完整求和,那么无论您在哪个设备上执行内核,您最终都会失去准确性。您可以采取一些措施来获得正确答案:
- 如果您的平台支持,请使用 double 而不是 float
- 使用 int 或 unsigned int
- 对较小的一组数字求和,例如:0+1+2+...+4095+4096 = (2^23 + 2^11)
我使用 AMD's two-stage reduction example 使用浮点精度计算从 0 到 65 536 的所有数字的总和。不幸的是,结果不正确。但是,当我修改我的代码,以便计算 65 536 个较小数字(例如 1)的总和时,结果是正确的。
我在代码中找不到任何错误。由于 float 类型,我是否有可能得到错误的结果?如果是这种情况,解决问题的最佳方法是什么?
这是使用有限精度 CPU 或 GPU 对浮点数求和的 "side effect"。准确性取决于算法和值求和的顺序。背后的理论和实践在 Nicholas J, Higham 的论文中解释
浮点求和的精度
解决方法是使用更智能的算法,例如 Kahan 求和算法
https://en.wikipedia.org/wiki/Kahan_summation_algorithm
海厄姆论文也有一些替代方案。
这个问题说明了基准测试的本质,基准测试的第一条规则是获得 正确答案,使用真实数据!
您的内核或主机应用程序的编码可能没有错误。问题出在单精度浮点数上。
正确的和是:65537 * 32768 = 2147516416,用二进制表示需要 31 位 (10000000000000001000000000000000)。 32 位浮点数最多只能精确保存 2^24 的整数。
"Any integer with absolute value less than [2^24] can be exactly represented in the single precision format" "Floating Point" article, wikipedia
这就是当总和小于或等于 2^24 时得到正确总和的原因。如果您使用单精度进行完整求和,那么无论您在哪个设备上执行内核,您最终都会失去准确性。您可以采取一些措施来获得正确答案:
- 如果您的平台支持,请使用 double 而不是 float
- 使用 int 或 unsigned int
- 对较小的一组数字求和,例如:0+1+2+...+4095+4096 = (2^23 + 2^11)