我使用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可以减少以下表达式:
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