平均値を求める | Programming Place Plus C++編 逆引き

トップページC++編逆引き

C++編で扱っている C++ は 2003年に登場した C++03 という、とても古いバージョンのものです。C++ はその後、C++11 -> C++14 -> C++17 -> C++20 と更新されており、今後も 3年ごとに更新されます。
なかでも C++11 での更新は非常に大きなものであり、これから C++ の学習を始めるのなら、C++11 よりも古いバージョンを対象にするべきではありません。特に事情がないなら、新しい C++ を学んでください。 当サイトでは、C++14 をベースにした新C++編を作成中です。

目的

要素が数値の配列やコンテナがあるとき、その要素の値の平均値を求めたいとします。

方法①(合計を求めて、要素数で割る)[C++03~]

基本的にはやり方は1つで、合計を求めて、要素数で割るだけです。

合計を求める方法は、「合計を求める」で、要素数を求める方法は「要素数を求める」で説明していますから、それらの組み合わせで実現できます。

#include <iostream>
#include <list>
#include <numeric>

#define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof(array[0]))

int main()
{
    // 配列の例
    int array[] = {0, 1, 2, 3, 4};
    int arraySum = std::accumulate(array, array + SIZE_OF_ARRAY(array), 0);
    int arrayAvg = arraySum / SIZE_OF_ARRAY(array);
    std::cout << arrayAvg << std::endl;

    // std;;list の例
    std::list<int> lst(array, array + SIZE_OF_ARRAY(array));
    int lstSum = std::accumulate(lst.begin(), lst.end(), 0);
    int lstAvg = lstSum / lst.size();
    std::cout << lstAvg << std::endl;
}

実行結果:

2
2

実戦的には、ゼロ除算にならないように注意する必要があります。このサンプルプログラムでは、「lst.size()」が 0 を返す可能性を考慮しなければなりません。

なお、整数型の値の平均値を、実数で得たい場合は、double型などで計算を行う必要があります。

double arrayAvg = static_cast<double>(arraySum) / SIZE_OF_ARRAY(array);

次に、関数化することを考えます。配列やコンテナに適用できるように、STLアルゴリズムの形を真似て作ってみます。

#include <cassert>
#include <iostream>
#include <iterator>
#include <list>
#include <numeric>

#define SIZE_OF_ARRAY(array) (sizeof(array)/sizeof(array[0]))

namespace {
    template <typename R, typename T>
    inline R average(const T begin, const T end, std::size_t n)
    {
        assert(n >= 0);
        return static_cast<R>(std::accumulate(begin, end, 0)) / n;
    }
}

int main()
{
    // 配列の例
    int array[] = {1, 2, 4, 5, 9};
    std::cout << average<double>(array, array + SIZE_OF_ARRAY(array), SIZE_OF_ARRAY(array))
              << std::endl;

    // std;;list の例
    std::list<int> lst(array, array + SIZE_OF_ARRAY(array));
    std::cout << average<double>(lst.begin(), lst.end(), lst.size())
              << std::endl;
}

実行結果:

4.2
4.2

2つのイテレータと、要素数を渡す形になっています。また、1つ目のテンプレート仮引数が、戻り値の型を表しており、整数型の値の平均値を、実数で受け取るようなことにも対応できます。

要素数については、std::distance関数を使って算出できますが、イテレータのカテゴリ(【標準ライブラリ】第14章参照)が、ランダムアクセスイテレータでない場合(list の場合など)の効率面を考えると、素直に渡してあげた方が良いと思います。


参考リンク


更新履歴

’2017/6/1 新規作成。



逆引きのトップページへ

C++編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る