数値演算の STLアルゴリズム | Programming Place Plus C++編【標準ライブラリ】 第24章

トップページC++編

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

この章の概要

この章の概要です。


数値演算の STLアルゴリズム

この章では、STLアルゴリズムの中から、数値演算を行うものを取り上げます。

ただし、実のところ、数値演算だけに特化しているとは限りません。たとえば、accumulate関数は +演算子を使うことによって合計を求めているので、+演算子によって連結を意味する std::string のような型を対象にすれば、数値演算以外の意味で使うことが可能です。

なお、数値演算の STLアルゴリズムは、<algorithm> ではなく、<numeric> という標準ヘッダに含まれています

accumulate

accumulate関数は、指定した範囲内の要素の合計を計算します。

namespace std {
    template <typename InputIterator, typename T>
    T accumulate(InputIterator first, InputIterator last, T init);

    template <typename InputIterator, typename T, typename BinaryOperation>
    T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op);
}

第1、2引数で指定した範囲内の要素の合計を求めます。第3引数は初期値として機能します。戻り値は、結果(合計)を返します。

1つ目の形式では、合計を +演算子を使って計算します。具体的には、各要素(elem) について「init = init + elem」を行います。

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

int main()
{
    std::vector<int> v;
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);

    std::cout << std::accumulate(v.begin(), v.end(), 0) << std::endl;
}

実行結果

10

2つ目の形式では、第4引数に指定した関数や関数オブジェクトを使って計算します。

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

int main()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    std::cout << std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>()) << std::endl;
}

実行結果

120

std::multiplies は、標準で用意されている関数オブジェクトです。std::multiplies が呼び出されると、2つの引数に *演算子を適用した結果を返します。

標準の関数オブジェクトについては、第26章で取り上げます。

inner_product

inner_product関数は、指定した2つの範囲内の要素の内積を計算します。

namespace std {
    template <typename InputIterator1, typename InputIterator2, typename T>
    T inner_product(InputIterator1 first1, InputIterator1 last1,InputIterator2 first2, T init);

    template <typename InputIterator1, typename InputIterator2, typename T, typename BinaryOperation1, typename BinaryOperation2>
    T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2);
}

第1、2引数で1つ目の範囲を指定し、第3引数でもう1つの範囲の先頭の位置を指定します。第4引数は初期値として機能します。戻り値は、結果(合計)を返します。

1つ目の形式では、*演算子を使って計算します。具体的には、1つ目の範囲の各要素(elem1) と、2つ目の範囲の各要素(elem2) について、「init = init + elem1 * elem2」を行います。つまり、2つの要素の積の合計ということになります。

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

int main()
{
    std::vector<int> v;
    v.push_back(0);
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);

    std::cout << std::inner_product(v.begin(), v.end(), v.begin(), 0) << std::endl;
}

実行結果

30

2つ目の形式では、第5引数(op1) と第6引数(op2) に指定した関数や関数オブジェクトを使って、「init = op1(init, op2(elem1, elem2))」という計算を行います。

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

int main()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    std::cout << std::inner_product(v.begin(), v.end(), v.begin(), 1, std::multiplies<int>(), std::plus<int>()) << std::endl;
}

実行結果

3840

std::multiplies や std::plus は、標準で用意されている関数オブジェクトです。std::multiplies が呼び出されると、2つの引数に *演算子を適用した結果を返し、std::plus の方は、+演算子を適用した結果を返します。

標準の関数オブジェクトについては、第26章で取り上げます。

partial_sum

partial_sum関数は、指定した範囲内の要素の部分和を計算します。

namespace std {
    template <typename InputIterator, typename OutputIterator>
    OutputIterator partial_sum(InputIterator first, InputIterator last, OutputIterator result);

    template <typename InputIterator, typename OutputIterator, typename BinaryOperation>
    OutputIterator partial_sum(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op); 
}

第1、2引数で指定した範囲内の要素を先頭から順に調べ、そこまでの和を、第3引数の範囲へ出力します。つまり、1つ目の範囲の要素を elem0、elem1、elem2・・・とすると、2つ目の範囲には、次の値が出力されます。[elem0, elem0 + elem1, elem0 + elem1 + elem2, ・・・」

和の計算には、1つ目の形式では +演算子が使われ、2つ目の形式では第4引数の関数や関数オブジェクトが使われます。

戻り値は、最後に出力された要素を指すイテレータです。

#include <numeric>
#include <iostream>
#include <vector>
#include <algorithm>

namespace {
    void Println(int elem)
    {
        std::cout << elem << std::endl;
    }
}

int main()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(3);
    v.push_back(4);
    v.push_back(5);

    std::vector<int> result(v.size());
    std::partial_sum(v.begin(), v.end(), result.begin());

    std::for_each(result.begin(), result.end(), Println);
}

実行結果

1
3
6
10
15


adjacent_difference

adjacent_difference関数は、指定した範囲内の要素の階差を計算します。

namespace std {
    template <typename InputIterator, typename OutputIterator>
    OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result);

    template <typename InputIterator, typename OutputIterator, typename BinaryOperation>
    OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op); 
}

第1、2引数で指定した範囲内の要素を先頭から順に調べ、手前の要素との差を、第3引数の範囲へ出力します。つまり、1つ目の範囲の要素を elem0、elem1、elem2・・・とすると、2つ目の範囲には、次の値が出力されます。[elem0, elem1 - elem0, elem2 - elem1, ・・・」

差の計算には、1つ目の形式では -演算子が使われ、2つ目の形式では第4引数の関数や関数オブジェクトが使われます。

戻り値は、最後に出力された要素を指すイテレータです。

#include <numeric>
#include <iostream>
#include <vector>
#include <algorithm>

namespace {
    void Println(int elem)
    {
        std::cout << elem << std::endl;
    }
}

int main()
{
    std::vector<int> v;
    v.push_back(1);
    v.push_back(3);
    v.push_back(6);
    v.push_back(10);
    v.push_back(15);

    std::vector<int> result(v.size());
    std::adjacent_difference(v.begin(), v.end(), result.begin());

    std::for_each(result.begin(), result.end(), Println);
}

実行結果

1
2
3
4
5


練習問題

問題① accumulate関数を使って、指定範囲内の std::string の連結を行えることを確認してください。

問題② accumulate関数を使って、指定範囲内の std::string の長さの合計を求める処理を作成してください。


解答ページはこちら

参考リンク


更新履歴

’2018/1/5 コンパイラの対応状況について、対応している場合は明記しない方針にした。

’2017/7/30 clang 3.7 (Xcode 7.3) を、Xcode 8.3.3 に置き換え。

’2017/3/25 VisualC++ 2017 に対応。

’2016/12/3 新規作成。



前の章へ (第23章 ソートされた範囲を扱う STLアルゴリズム)

次の章へ (第25章 STL の関数オブジェクト)

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

Programming Place Plus のトップページへ



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