【问题标题】:Kahan summation algorithm has big computing error when it is compiled by GCCKahan求和算法在GCC编译时计算误差大
【发布时间】:2016-05-27 14:37:24
【问题描述】:

我使用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;
}

如果使用MSVS编译的话可以正常使用,但是使用GCC的时候会出现很大的计算错误。

问题出在哪里?

【问题讨论】:

  • 你说的我使用GCC时出现大计算错误是什么意思?能详细点吗?
  • 显示编译器标志和生成的汇编代码
  • 我们可以自己获取汇编代码。为了能够回答这个问题,我们真正需要的是一些样本输入和预期输出。以及您看到的错误消息(如果有)。比如,您可能忘记包含定义size_t 的标准库头文件?
  • 维基页面有一个很好的评论:“小心过度激进的优化编译器!”可能你应该减少这部分代码的优化。

标签: c++ algorithm gcc


【解决方案1】:

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

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

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

因为这种转换在数学上是正确的,但这种优化会扼杀 Kahan 算法。

为了避免这个问题,您可以使用“-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 

【讨论】:

  • 我没有看到任何证据表明 GCC 正在执行您描述的激进操作,除非有意启用不安全的数学优化(例如,通过抛出 -ffast-math 开关)。这不是默认值,即使在 -O3 时也是如此。据我所知,不可能。浮点计算有严格的规定。
  • 或在变量之一上使用“volatile”关键字,例如“temp”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-15
  • 1970-01-01
  • 2018-03-15
  • 1970-01-01
  • 2016-06-05
  • 1970-01-01
相关资源
最近更新 更多