从整数向量中获取平均值

时间:2016-03-06 22:22:20

标签: c++ vector

我一直无法找到一种从C ++中的整数向量中获取平均值的方法。

我无法开始添加所有值,因为我可能会超过接受的最大整数值。

如何有效,快速地计算出来? C ++语言中是否有标准库可以做到这一点?

3 个答案:

答案 0 :(得分:24)

go-to方法只是用std::accumulate

的足够宽的整数类型求和
double avg1(std::vector<int> const& v) {
    return 1.0 * std::accumulate(v.begin(), v.end(), 0LL) / v.size();
}

如果这个总和溢出(2300万英寸,平均值必须至少为4.01x10 11 - 也就是说,它不会溢出这甚至都不适合int32_t ......所以你的方式很好,但是如果你获得几个数量级的数字,或者有更宽的int类型,那么您可以使用常用的“在线”算法来计算平均值:

double avg2(std::vector<int> const& v) {
    int n = 0;
    double mean = 0.0;
    for (auto x : v) {
        double delta = x - mean;
        mean += delta/++n;
    }
    return mean;
}

这不会溢出,不是很容易失去精度,但由于重复的额外划分可能会更昂贵。

答案 1 :(得分:1)

  

我一直无法找到从a获得平均值的方法   C ++中的整数向量。我无法开始添加所有内容   值因为我可以超过最大整数接受值。怎么样   我可以有效而快速地计算出来吗?有没有标准   C ++中的库。

关于找到一个对于uint64_t而言可能太大的总和的讨论很多。

所以请遵循这个建议,不要再担心......

我已经使用过,可以推荐,并且对于名为&#34; gmpxx.h&#34;的多精度C ++库印象非常深刻。

我已经将它用于了几项有趣的工作,包括生成一个没有明显努力的大型斐波那契的代码。它易于使用,而且速度惊人,我在网上找到了如何使用的例子。

代码段:

mpz_class  n;   // a multi-precision integer, 
n = 1;          // easy initialize
size_t F = 1000; 
for (size_t i=1; i<=F; ++i)
   n = n * i;
// show
std::string Fstr = digiComma(n);  // inserts comma's
std::cout << "\n" << F << "! = " << Fstr
          << "\n" << digitCnt(Fstr) << " bytes " <<  std::endl;

我的输出是2568个字符(&gt; 1900位),逗号分隔,&lt;中的大int值20毫秒。

  

1000! =   402,387,260,077,093,773,543,702,433,923,003,985,719,374,864,210,714,632,543,799,           910,429,938,512,398,629,020,592,044,208,486,969,404,800,479,988,610,197,196,058,           631,666,872,994,808,558,901,323,829,669,944,590,997,424,504,087,073,759,918,823,           627,727,188,732,519,779,505,950,995,276,120,874,975,462,497,043,601,418,278,094,           646,496,291,056,393,887,437,886,487,337,119,181,045,825,783,647,849,977,012,476,           632,889,835,955,735,432,513,185,323,958,463,075,557,409,114,262,417,474,349,347,           553,428,646,576,611,667,797,396,668,820,291,207,379,143,853,719,588,249,808,126,           867,838,374,559,731,746,136,085,379,534,524,221,586,593,201,928,090,878,297,308,           431,392,844,403,281,231,558,611,036,976,801,357,304,216,168,747,609,675,871,348,           312,025,478,589,320,767,169,132,448,426,236,131,412,508,780,208,000,261,683,151,           027,341,827,977,704,784,635,868,170,164,365,024,153,691,398,281,264,810,213,092,           761,244,896,359,928,705,114,964,975,419,909,342,221,566,832,572,080,821,333,186,           116,811,553,615,836,546,984,046,708,975,602,900,950,537,616,475,847,728,421,889,           679,646,244,945,160,765,353,408,198,901,385,442,487,984,959,953,319,101,723,355,           556,602,139,450,399,736,280,750,137,837,615,307,127,761,926,849,034,352,625,200,           015,888,535,147,331,611,702,103,968,175,921,510,907,7​​88,019,393,178,114,194,545,           257,223,865,541,461,062,892,187,960,223,838,971,476,088,506,276,862,967,146,674,           697,562,911,234,082,439,208,160,153,780,889,893,964,518,263,243,671,616,762,179,           168,909,779,911,903,754,031,274,622,289,988,005,195,444,414,282,012,187,361,745,           992,642,956,581,746,628,302,955,570,299,024,324,153,181,617,210,465,832,036,786,           906,117,260,158,783,520,751,516,284,225,540,265,170,483,304,226,143,974,286,933,           061,690,897,968,482,590,125,458,327,168,226,458,066,526,769,958,652,682,272,807,           075,781,391,858,178,889,652,208,164,348,344,825,993,266,043,367,660,176,999,612,           831,860,788,386,150,279,465,955,131,156,552,036,093,988,180,612,138,558,600,301,           435,694,527,224,206,344,631,797,460,594,682,573,103,790,084,024,432,438,465,657,           245,014,402,821,885,252,470,935,190,620,929,023,136,493,273,497,565,513,958,720,           559,654,228,749,774,011,413,346,962,715,422,845,862,377,387,538,230,483,865,688,           976,461,927,383,814,900,140,​​767,310,446,640,259,899,490,222,221,765,904,339,901,           886,018,566,526,485,061,799,702,356,193,897,017,860,040,811,889,729,918,311,021,           171,229,845,901,641,921,068,884,387,121,855,646,124,960,798,722,908,519,296,819,           372,388,642,614,839,657,382,291,123,125,024,186,649,353,143,970,137,428,531,926,           649,875,337,218,940,694,281,434,118,520,158,014,123,344,828,015,051,399,694,290,           153,483,077,644,569,099,073,152,433,278,288,269,864,602,789,864,321,139,083,506,           217,095,002,597,389,863,554,277,196,742,822,248,757,586,765,752,344,220,207,573,           630,569,498,825,087,968,928,162,753,848,863,396,909,959,826,280,956,121,450,994,           871,701,244,516,461,260,379,029,309,120,889,086,942,028,510,640,182,154,399,457,           156,805,941,872,748,998,094,254,742,173,582,401,063,677,404,595,741,785,160,829,           230,135,358,081,840,096,996,372,524,230,560,855,903,700,624,271,243,416,909,004,           153,690,105,933,983,835,777,939,410,970,027,753,472,000,000,000,000,000,000,000,           000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,           000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,           000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,           000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000

2568字节

真正的0m0.013s

用户0m0.004s

sys 0m0.000s

那么uint64_t有多大?我认为适合uint64_t的最大Fib是Fib(93)。

答案 2 :(得分:0)

诀窍是您不必存储向量的全部和。您可以在迭代过程中对整数进行除法,然后存储余数以将其添加到下一个值。

这允许创建非常高效的内存算法。我没有进行基准测试,但是对于具有硬件划分模块的处理器应该可以。

对于矢量的每个元素,只要el + vector.size()适合ACCU_T,这里的解决方案就不会溢出。如果我们使用处理器溢出标志,应该可以消除此限制。

template<typename T, typename ACCU_T = uintmax_t>
T vec_average(const std::vector<T> &vec)
{
    const ACCU_T size = (ACCU_T)vec.size();
    T avg = 0;
    ACCU_T accu = 0;
    for (const T &el : vec)
    {
        accu += (ACCU_T)el;
        avg += (T)(accu / size);
        accu %= size;
    }
    return avg;
}

它不使用任何浮点数或大数字。 accu的变量在函数末尾的值为sum(vec) % vec.size()


是的,这是GCC和Clang的版本,对于任何无符号整数都不会溢出。

(这里的确切约束是el + vector.size()不能大于ACCU_T可以容纳的2倍。)

template<typename T, typename ACCU_T = uintmax_t>
T vec_average(const std::vector<T> &vec)
{
    const ACCU_T size = (ACCU_T)vec.size();
    const T overflowAvg = (T)((ACCU_T(-1)) / size);
    const ACCU_T overflowAccu = overflowAvg * size;
    T avg = 0;
    ACCU_T accu = 0;
    for (const T &el : vec)
    {
        if (__builtin_add_overflow(accu, (ACCU_T)el, &accu))
        {
            avg += overflowAvg;
            accu -= overflowAccu;
        }
        avg += (T)(accu / size);
        accu %= size;
    }
    return avg;
}