Kahan求和算法在GCC编译时存在较大的计算错误

Kahan summation algorithm has big computing error when it is compiled by GCC

本文关键字:计算 错误 存在 算法 求和 GCC 编译 Kahan      更新时间:2023-10-16

我使用Kahan求和算法:

inline void KahanSum(float value, float & sum, float & correction)
{
    float term = value - correction;
    float temp = sum + term;
    correction = (temp - sum) - term;
    sum = temp; 
}
float KahanSum(const float * ptr, size_t size)
{
    float sum = 0, correction = 0;
    for(size_t i = 0; i < size; ++i)
        KahanSum(ptr[i], sum, correction);
    return sum;
}

如果使用 MSV 编译它,它可以正常工作,但是当我使用 GCC 时,它有一个很大的计算错误。

这里的麻烦在哪里?

我假设,这是积极的编译器优化的结果。因此,GCC 可以将表达式从:

    float term = value - correction;
    float temp = sum + term;
    correction = (temp - sum) - term;
    sum = temp;

    float term = value - correction;
    correction = 0;
    sum += term;

因为这种转换在数学上是正确的,但这种优化杀死了卡汉算法。

为了避免这个问题,您可以使用"-O1"GCC编译器选项来编译代码。它将是这样的:

#if defined(__GNUC__)
#  pragma GCC push_options
#  pragma GCC optimize ("O1")
#endif 
inline void KahanSum(float value, float & sum, float & correction)
{
    float term = value - correction;
    float temp = sum + term;
    correction = (temp - sum) - term;
    sum = temp; 
}
float KahanSum(const float * ptr, size_t size)
{
    float sum = 0, correction = 0;
    for(size_t i = 0; i < size; ++i)
        KahanSum(ptr[i], sum, correction);
    return sum;
}
#if defined(__GNUC__)
#  pragma GCC pop_options
#endif