web-dev-qa-db-ja.com

std :: accumulateとラムダを使用して平均を計算するにはどうすればよいですか?

大量の標準ライブラリコンテナを持っているので、それらを一緒に追加するとオーバーフローが発生する可能性があります。このコンテナであるとしましょう:

_std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
_

Std :: accumulateを使用して、このコンテナーの平均を計算したいのですが、すべての数値を足し合わせることができません。 v[0]/v.size() + v[1]/v.size() + ...で計算します。だから私は設定しました:

_auto lambda = ...;
std::cout << std::accumulate(v.begin(), v.end(), 0, lambda) << std::endl;
_

これが私がこれまでに試したことです。ここで、_->_は出力を示します。

_lambda = [&](int a, int b){return (a + b)/v.size();};  ->  1
lambda = [&](int a, int b){return a/v.size() + b/v.size();};  ->  1
lambda = [&](int a, int b){return a/v.size() + b;};  ->  10
_

出力が_5_になるような正しい平均をどのように生成できますか?

20
EMBLEM

結果を保存するために整数を使用すべきではありません:

関数に渡される戻り値の型 accumulate
T accumulate( InputIt first, InputIt last, T init, BinaryOperation op );は3番目のパラメータータイプに依存します:(T init)したがって、そこに配置する必要があります:0.0からdoubleとして結果を取得します。

#include <vector>
#include <algorithm>
#include <iostream>
#include <numeric>
using namespace std;
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

int main()
{
    auto lambda = [&](double a, double b){return a + b / v.size(); };
    std::cout << std::accumulate(v.begin(), v.end(), 0.0, lambda) << std::endl;
}
18
AdamF

これはうまく丸められないかもしれませんが、コンテナにsize()メソッドがない場合でも機能します。

_auto lambda = [count = 0](double a, int b) mutable { return a + (b-a)/++count; };
_

これは、C++ 14の新しい機能である初期化されたキャプチャを利用して、ラムダ内に状態を格納します。 (追加のローカル変数のキャプチャを介して同じことを行うことができますが、そのスコープはラムダのライフタイムではなくローカルスコープです。)古いC++バージョンの場合は、countstructのメンバー変数を使用して、ラムダ本体をそのoperator()()実装として配置します。

丸め誤差の蓄積を防ぐ(または少なくとも劇的に減らす)には、次のようにします。

_auto lambda = [count = 0, error = 0.0](double a, int b) mutable {
   const double desired_change = (b-a-error)/++count;
   const double newa = a + (desired_change + error);
   const double actual_change = newa - a;
   error += desired_change - actual_change;
   return newa;
};
_
7
Ben Voigt

実行中の「平均」はラムダの最初のパラメーターであるため、以下は正しいです。

lambda = [&](int a, int b){return a + b/v.size();};
1
Ken Bloom

使用している3つのラムダ関数は、マークまでありません。

lambda = [&](int a, int b){return (a + b)/v.size();};  ->  1
lambda = [&](int a, int b){return a/v.size() + b/v.size();};  ->  1
lambda = [&](int a, int b){return a/v.size() + b;};  ->  10

ここで使用されるパラメーターaは、特定の時点でのベクトルの特定のインデックスまでの平均を運びます。たとえば、「b」の値が1の場合の「a」の値は0.0であり、「b」がその瞬間に2になる場合「0.1」である必要があります。次に、ラムダ関数が呼び出されるたびに「a」をv.size()で除算する必要がないことは明らかです。

言及された状況に適切なラムダ関数に来る

lambda = [&](double x,double y){return x+y/v.size();}

ここでは、v.size()の値が必要なため、参照によってキャプチャします。事前にわかっている場合は、ベクトルのサイズの値を事前に渡すことができます。

作業プログラムは

    #include<iostream>
    #include<numeric>
    #include<vector>
    using namespace std;

    int main(){
        vector<int> v(10);
        iota(v.begin(),v.end(),1);
        double x=accumulate(v.begin(),v.end(),0.0,[&](double x,double y) {return x+y/v.size();});
        cout << x << endl;
    }

PS: 'iota'は範囲を増加させる方法で初期化するために使用され、ここでは1から10までのベクトルを初期化します

0
Pyder