总结庞大的数字

时间:2013-07-09 08:47:15

标签: c++ windows visual-studio-2010 average

情况就是这样,我真的不知道在为对方增加大数字来计算最后的平均值时究竟发生了什么。

如果要编辑特定错误,请更正我。

我已经调试了,我只是在数据中查找,我的常规数据在下面的循环中,但似乎变量“somme”给了我一些随机数字,并给出了一些完全错误的东西。 “moyenne”也是如此

其他,所有数据都是,或0或正数。 Somme有时会给出负数!

#define Nb 230400
std::vector<std::array<double,480>> data(480);

    double somme=0;
    double moyenne=0;
    for (int i=0;i<480;i++)
    {
        for (int j=0;j<480;j++)
            somme=somme+data[i][j];

    }
    moyenne=somme/Nb;

3 个答案:

答案 0 :(得分:2)

首先,根据您提供的代码,您无法获得 负面结果(至少使用IEEE浮点数 PC和通常的Unix机器);如果你溢出,你会得到 特殊值Inf(但如果数据是,则不能溢出 在您指定的范围内)。结果可能是错误的,原因是 舍入错误,但它们的下限仍为0.

您尚未指定确定结果的方式 否定,以及如何确保输入数据在范围内,所以 我只能推测;但以下是不同的 可能性:

  • 你打开优化后编译,你正在寻找 在调试器的值。调试器经常显示 查看优化后的错误值(未初始化的内存) 代码。
  • 您在其他地方有未定义的行为(指针问题), 这会破坏你在这里看到的记忆。 99%的人 时间,这是其他无法解释的探索 行为,但我在这里有点怀疑:只要有 您发布的代码序列中没有别的,也没有 其他线程运行,没有指针(至少是你 操纵)滥用。
  • 您未能正确初始化数据。你可能想要 在最里面的循环中添加一个断言,只是为了确定:
        for ( int i = 0; i < 480; ++ i ) {
            for ( int j = 0; j < 480; ++ j ) {
                assert( data[i][j] >= 0.0 && data[i][j] < 200000.0 );
                somme += data[i][j];
            }
        }
    

对于其他人,您的算法不是特别准确。一些 快速测试(使用随机值填充数据结构) 范围[0...2e5))显示小于15位的准确度 最后结果。 (当然,这可能是可以接受的。大多数 您获得的物理数据不会超过3或 无论如何,4位精度,你可能不会显示更多 比6.在这种情况下...)

准确性问题实际上很奇怪,并且显示了如何 这些东西可能很棘手。我用了三个函数 测试:

//  Basically what you did...
double
av1( std::vector<std::array<double, cols>> const& data )
{
    double somme = 0.0;
    for ( int i = 0; i != data.size(); ++ i ) {
        for ( int j = 0; j != cols; ++j ) {
            somme += data[i][j];
        }
    }
    return somme / (data.size() * cols);
}

//  The natural way of writing it in C++11...
double
av2( std::vector<std::array<double, cols>> const& data )
{
    return std::accumulate( 
        data.begin(),
        data.end(),
        0.0,
        []( double a, std::array<double, cols> const& b ) {
            return a + std::accumulate( b.begin(), b.end(), 0.0 );
        } ) / (data.size() * cols);
}

//  Using the Kahan summation algorithm...
double
av3( std::vector<std::array<double, cols>> const& data )
{
    double somme = 0.0;
    double c = 0.0;
    for ( int i = 0; i != data.size(); ++ i ) {
        for ( int j = 0; j != cols; ++j ) {
            double y = data[i][j] - c;
            double t = somme + y;
            c = (t - somme) - y;
            somme = t;
        }
    }
    return somme / (data.size() * cols);
}

(在所有测试中,cols == 480data.size() == 480。)

代码是使用VC11编译的,带有选项/ O2。该 有趣的是av2系统地更多 比你的代码准确,通常低至第17位(2或 内部表示中的3位),其中as av1经常在第15位(8或更高)中关闭2或3 内部表示中的9位)。原因是 你的代码系统地收集到xmm1,所有 480*480值,av2分别收集每一行; 这导致较少的添加与较大的差异 大小。 (当av1接近数据末尾时,somme 接近2.3e10,它明显大于任何一个 数据元素。)使用类似的东西:

double
moyenne( std::vector<std::array<double, cols>> const& data )
{
    double outerSum = 0.0;
    for ( int i = 0; i != data.size(); ++ i ) {
        double innerSum = 0.0;
        for ( int j = 0; j != cols; ++ j ) {
            innerSum += data[i][j];
        }
        outerSum += innerSum;
    }
    return outerSum / (data.size() * cols);
}

应该给出相当于av2的结果。 (但如果你需要的话 准确性,你真的应该与卡汉总结 算法。)

(我很想补充一点,如果你有任何惊喜,那么你 反正不应该使用浮点。)

答案 1 :(得分:1)

可能发生数据溢出。溢出改变了符号位,因此它看起来像一个负数。 如果你正在处理非常大的数字,请尝试“long double”而不是“double”。

答案 2 :(得分:0)

这也可能是由浮点错误引起的。如果您添加不同维度的数字(例如10e-10 + 10),浮点误差可能非常大,而如果维度相似则误差较小。

如果所有数字都很大,那么您的代码应该有效(如果没有溢出)。如果没有,如果添加已排序的数字,则可以提高准确性。伪代码:

array a;
sort(a);
foreach i in a:
    somme += i
somme /= count(a)

原因是,总结的最小数字可能与下一个更大的数字更相似。这样,错误就会变小。

为避免溢出,您可以通过计数(a)将每个i分开,而不是分配结果。如果没有发生溢出,这不应该改变准确性。

PS:如果你对数组进行降序排序或反转循环,你可以最大化你的错误!