最終更新日時: 2024年07月16日 18時43分27秒 (JST)
raclamusi が更新

履歴 編集

function template
<numeric>

# std::inner_product

    namespace std {
      template <class InputIterator1, class InputIterator2, class T>
      T inner_product(InputIterator1 first1,
                      InputIterator1 last1,
                      InputIterator2 first2,
                      T init);                        // (1) C++03
      template <class InputIterator1, class InputIterator2, class T>
      constexpr T
        inner_product(InputIterator1 first1,
                      InputIterator1 last1,
                      InputIterator2 first2,
                      T init);                        // (1) C++20

      template <class InputIterator1, class InputIterator2, class T,
                class BinaryOperation1, class BinaryOperation2>
      T inner_product(InputIterator1 first1,
                      InputIterator1 last1,
                      InputIterator2 first2,
                      T init,
                      BinaryOperation1 binary_op1,
                      BinaryOperation2 binary_op2);   // (2) C++03
      template <class InputIterator1, class InputIterator2, class T,
                class BinaryOperation1, class BinaryOperation2>
      constexpr T
        inner_product(InputIterator1 first1,
                      InputIterator1 last1,
                      InputIterator2 first2,
                      T init,
                      BinaryOperation1 binary_op1,
                      BinaryOperation2 binary_op2);   // (2) C++20
    }

## 概要

2つのシーケンスの内積(inner product)を計算する。

この関数は、イテレータ範囲`[first1, last1)`およびイテレータ範囲`[first2, first2 + (last1 - first1))`をそれぞれ任意次元のベクトルとみなし、その2つのベクトルの内積を計算する。

イテレータ範囲`[first1, last1)`をベクトル`v`、イテレータ範囲`[first2, first2 + (last1 - first1))`をベクトル`u`として、この関数は以下の効果を持つ：

- (1) : `init + (v[0] * u[0]) + (v[1] * u[1]) + … (v[N - 1] * u[N - 1])`
- (2) : `operator()+`を`binary_op1`、`operator*()`を`binary_op2`で代用して、(1)の演算を行う

## 要件

- C++03まで : `binary_op1`および`binary_op2`は、副作用を起こしてはならない
- C++11から : `binary_op1`および`binary_op2`が、イテレータ範囲`[first1, last1]`とイテレータ範囲`[first2, first2 + (last1 - first2)]`の要素変更およびイテレータの無効化をしてはならない

## テンプレートパラメータ制約

- 型`T`がコピー構築可能であること
- 型`T`がコピー代入可能であること

## 効果

- (1) :
  - C++03 : `acc = init;`、イテレータ範囲`[first1, last1)`の各イテレータを`i`、イテレータ範囲`[first2, first2 + (last1 - first1))`の各イテレータを`j`として、`acc = acc + (*i) * (*j);` の演算を行い、`acc`を返す
  - C++20 : `acc = init;`、イテレータ範囲`[first1, last1)`の各イテレータを`i`、イテレータ範囲`[first2, first2 + (last1 - first1))`の各イテレータを`j`として、`acc = std::move(acc) + (*i) * (*j);` の演算を行い、`acc`を返す
- (2) :
  - C++03 : `acc = init;`、イテレータ範囲`[first1, last1)`の各イテレータを`i`、イテレータ範囲`[first2, first2 + (last1 - first1))`の各イテレータを`j`として、`acc = binary_op1(acc, binary_op2((*i), (*j)));` の演算を行い、`acc`を返す
  - C++20 : `acc = init;`、イテレータ範囲`[first1, last1)`の各イテレータを`i`、イテレータ範囲`[first2, first2 + (last1 - first1))`の各イテレータを`j`として、`acc = binary_op1(std::move(acc), binary_op2((*i), (*j)));` の演算を行い、`acc`を返す

## 戻り値

演算によって求められた内積値を返す

## 計算量

`last1 - first1`をnであるとして、

- (1) : n 回の加算処理と n 回の乗算処理を行う。
- (2) : n 回の `binary_op1` 呼び出しと n 回の `binary_op2` 呼び出しを行う。

## 例

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

    int main()
    {
      // 任意次元のベクトルvとuの内積を求める。
      // v[0]はXベクトル、v[1]はYベクトル。
      const std::vector<float> v = {-1.0f, 1.0f};
      const std::vector<float> u = {1.0f, -2.0f};

      float result = std::inner_product(
                       v.begin(), v.end(), // ひとつ目のベクトル
                       u.begin(),          // ふたつ目のベクトル(v以上の次元数を持つこと)
                       0.0f);              // 内積の初期値(この値に対して加算が行われる)

      std::cout << result << std::endl;
    }

### 出力

    -3

## 実装例

    // (1)
    template <class InputIterator1, class InputIterator2, class T>
    T inner_product(InputIterator1 first1, InputIterator1 last1,
                    InputIterator2 first2, T init) {
      while (first1 != last1)
        init = std::move(init) + (*first1++ * *first2++);
      return init;
    }

    // (2)
    template <class InputIterator1, class InputIterator2, class T,
              class BinaryOperation1, class BinaryOperation2>
    T inner_product(InputIterator1 first1, InputIterator1 last1,
                    InputIterator2 first2, T init,
                    BinaryOperation1 binary_op1,
                    BinaryOperation2 binary_op2) {
      while (first1 != last1)
        init = binary_op1(std::move(init), binary_op2(*first1++, *first2++));
      return init;
    }

## 参照

- P0616R0 De-pessimize legacy `<numeric>` algorithms with `std::move`
- P1645R1 `constexpr` for `<numeric>` algorithms
  - C++20で、並列バージョン以外の数値計算アルゴリズムが`constexpr`対応した