2013-06-05 41 views
1

我得到一个意外的结果使用std :: accumulate与测试代码。我试图加起来双打的大载体,但由于某种原因,该值溢出:std :: accumulate按预期行事

#include <iostream> 
#include <vector> 
#include <functional> 
#include <numeric> 

using namespace std; 

double sum(double x, double y) 
{ 
    // slows things down but shows the problem: 
    //cout << x << " + " << y << endl; 
    return (x+y); 
} 

double mean(const vector<double> & vec) 
{ 
    double result = 0.0; 

    // works: 
    //vector<double>::const_iterator it; 
    //for (it = vec.begin(); it != vec.end(); ++it){ 
    //  result += (*it); 
    //} 

    // broken: 
    result = accumulate(vec.begin(), vec.end(), 0, sum); 

    result /= vec.size(); 

    return result; 
} 


int main(int argc, char ** argv) 
{ 

    const unsigned int num_pts = 100000; 

    vector<double> vec(num_pts, 0.0); 

    for (unsigned int i = 0; i < num_pts; ++i){ 
     vec[i] = (double)i; 
    } 

    cout << "mean = " << mean(vec) << endl; 

    return 0; 
} 

的部分输出从COUT之内:

2.14739e + 09 + 65535
2.14745e + 09 + 65536
-2.14748e + 09 + 65537
-2.14742e + 09 + 65538
-2.14735e + 09 + 65539 ​​

正确的输出(迭代):

平均值= 49999.5

不正确的输出(使用累加):

平均值= 7049.5

我可能会犯一个累赘的错误?我已经使用累积成功之前...

感谢

+2

'stl :: accumulate'? '的std :: algorithm'?是的,你很累。 –

+1

因为SUM(0..n)=(n)(n + 1)/ 2,它恰好在n = 65536上溢出。数学不是很好 – Wug

+0

您可能想使用[Kahan Summation](https://en.wikipedia.org/wiki/Kahan_summation_algorithm)。看到我的答案[总和双小数C++](http://stackoverflow.com/questions/10330002/sum-of-small-double-numbers-c)。 –

回答

8

你需要传递一个doubleaccumulate

result = accumulate(vec.begin(), vec.end(), 0.0, sum); 
              ^^^ 

否则使用int,然后将结果转换为双执行蓄积。

+0

一分三十分秒。它让我惊讶你有多快注意到这样的事情。 +1 – Wug

+0

@Wug我们可能在之前犯过同样的错误:) – juanchopanza

+10

@Wug:这是一个标准gotcha与'std :: accumulate'。有一半的人可能在页面甚至被加载之前猜出了答案,仅仅是从标题中。 –