Skip to the content of the web site.

The numeric library

These functions are found in the #include <numeric> library. In this document, let T represent any type name.

void std::iota( itr_t itr_first, itr_t itr_last, T initial )

This function assigns initial assigns *itr_first = initial and then for each successive entry, that entry is assigned the result after performing ++initial.

Thus, by default, assuming that the iterators are referring to a container storing int,

    std::iota( itr_first, itr_last, 0 );

fills the entries of the range with $0, 1, 2, 3, \ldots$. The algorithm can be implemented as follows:

    while ( itr_first != itr_last ) {
      *itr_first = initial;
      ++itr_first;
      ++initial;
    }

T std::inner_product( itr_t itr_1_first, itr_t itr_1_last, itr_t itr_2_first, T initial )
T std::inner_product( itr_t itr_1_first, itr_t itr_1_last, itr_t itr_2_first, T initial, T multiplies( T, T ), T plus( T, T ) )

These calculates an inner product and are equivalent to:

    while ( itr_1_first != itr_1_last ) {
      // First declaration
      initial += *itr_1_first * *itr_2_first;
      // Second declaration
      // initial = plus( initial, multiplies( *itr_1_first, *itr_2_first ) );
      ++itr_1_first;
      ++itr_2_first;
    }

Note that we assume that there are sufficiently many entries in the range starting at itr_2_first.

Note that the following are equivalent calls if we #include <functional> with

     std::cout << std::inner_product(
       itr_1_first, itr_1_last, itr_2_first, initial
     ) << std::endl;

     std::cout << std::inner_product(
       itr_1_first, itr_1_last, itr_2_first, initial,
       std::multiplies<T>(), std::plus<T>()
     ) << std::endl;

T std::accumulate( itr_t itr_first, itr_t itr_last, T initial )
T std::accumulate( itr_t itr_first, itr_t itr_last, T initial, T plus( T, T ) )

These function adds the values on the range to the initial value. They are equivalent to:

    while ( itr_first != itr_last ) {
      // First declaration
      initial += *itr_first
      // Second declaration
      // initial = plus( initial, *itr_first );
      ++itr_first;
    }

The following two are equivalent:

     std::cout << std::accumulate(
       itr_first, itr_last, initial
     ) << std::endl;

     std::cout << std::accumulate(
       itr_first, itr_last, initial,
       std::plus<T>()
     ) << std::endl;

T std::reduce( itr_t itr_first, itr_t itr_last, T initial )
T std::reduce( itr_t itr_first, itr_t itr_last, T initial, T plus( T, T ) )

These functions are similar to std::accumulate, but the operations can be spread across multiple threads; thus, half the range may be added on one core, the other half on another, and then the results are added to initial. If a function is passed, it must be both commutative and associative: that is,

              plus( x, y ) == plus( y, x )
   plus( x, plus( y, z ) ) == plus( plus( x, y ), z )

The function "plus" is often described to as the "reduction".

T std::transform_reduce( itr_t itr_1_first, itr_t itr_1_last, itr_t itr_2_first, T initial )
T std::transform_reduce( itr_t itr_1_first, itr_t itr_1_last, itr_t itr_2_first, T initial, T multiplies( T, T ), T plus( T, T ) )

These are similar to std::inner_product, only they can be run in parallel. The function plus(...) must be both commutative and associative. Very often, the function "multiplies" is called "transform" and the function "plus" is called the "reduction"; hence the name of the function.

T std::transform_reduce( itr_t itr_first, itr_t itr_last, T initial, T transform( T ), T reduce( T, T ) )

This is similar to std::accumulate, only the function transform(...) is applied to each entry of the range before it is passed to reduce(...), the function that parallels plus(...) in std::accumulate. The function reduce(...) must be both commutative and associative.

The returned iterator defines the right-hand side of the range encompassing the output.

itr_t std::partial_sum( itr_t itr_first, itr_t itr_last, itr_t itr_out )
itr_t std::partial_sum( itr_t itr_first, itr_t itr_last, itr_t itr_out, T plus( T, T ) )

This calculates a partial sum, copying the partial sum to the location specified by itr_out. It is equivalent to:

    // Assuming the range is not empty
    T value{ *itr_first };
    *itr_out = value;

    ++itr_first;
    ++itr_out;

    while ( itr_first != itr_last ) {
      // First declaration
      value += *itr_first;
      // Second declaration
      // value = plus( value, *itr_first );
      *itr_out = value;

      ++itr_first;
      ++itr_out;
    }

The returned iterator defines the right-hand side of the range encompassing the output.

itr_t std::inclusive_scan( itr_t itr_first, itr_t itr_last, itr_t itr_out )
itr_t std::inclusive_scan( itr_t itr_first, itr_t itr_last, itr_t itr_out, T plus( T, T ) )
itr_t std::inclusive_scan( itr_t itr_first, itr_t itr_last, itr_t itr_out, T plus( T, T ), T initial )

This is similar to partial sum, but can be performed in parallel and is slightly more general. The first is equivalent to:

    // Assuming the range is not empty
    T value{ *itr_first };
    *itr_out = value;

    ++itr_first;
    ++itr_out;

    while ( itr_first != itr_last ) {
      // First declaration
      value += *itr_first;
      // Second declaration
      // value = plus( value, *itr_first );
      *itr_out = value;

      ++itr_first;
      ++itr_out;
    }

The third is equivalent to:

    while ( itr_first != itr_last ) {
      // Third declaration
      initial = plus( initial, *itr_first );
      *itr_out = initial;

      ++itr_first;
      ++itr_out;
    }

The first can be implemented as the third using std::plus<T>() and 0, while the second can be implemented as the third so long as the initial value is the identity element for the function at hand; for example, 0 for std::plus and 1 for std::multiplies.

The returned iterator defines the right-hand side of the range encompassing the output.

For example, the output of

  std::vector<int> u{ 2, 3, 2, 3, 1, 1, 2, 3, 5, 2 };
  std::cout << u << std::endl;

  std::vector<int> v( 10 );

  std::inclusive_scan( u.begin(), u.end(), v.begin() );
  std::cout << v << std::endl;

  std::inclusive_scan( u.begin(), u.end(), v.begin(), std::multiplies<int>() );
  std::cout << v << std::endl;

  std::inclusive_scan( u.begin(), u.end(), v.begin(), std::multiplies<int>(), 100 );
  std::cout << v << std::endl;

is

{2, 3, 2, 3, 1, 1, 2, 3, 5, 2}
{2, 5, 7, 10, 11, 12, 14, 17, 22, 24}
{2, 6, 12, 36, 36, 36, 72, 216, 1080, 2160}
{200, 600, 1200, 3600, 3600, 3600, 7200, 21600, 108000, 216000}

itr_t std::exclusive_scan( itr_t itr_first, itr_t itr_last, itr_t itr_out, T initial )
itr_t std::exclusive_scan( itr_t itr_first, itr_t itr_last, itr_t itr_out, T initial, T plus( T, T ) )

This is similar to partial sum, but can be performed in parallel and is slightly more general. The first is equivalent to:

    while ( itr_first != itr_last ) {
      *itr_out = initial;
      // First declaration
      initial += *itr_first;
      // Second declaration
      // initial = plus( initial, *itr_first );

      ++itr_first;
      ++itr_out;
    }

The third is equivalent to:

    while ( itr_first != itr_last ) {
      // Third declaration
      initial = plus( initial, *itr_first );
      *itr_out = initial;

      ++itr_first;
      ++itr_out;
    }

The first can be implemented as the third using std::plus<T>() and 0, while the second can be implemented as the third so long as the initial value is the identity element for the function at hand; for example, 0 for std::plus and 1 for std::multiplies.

The returned iterator defines the right-hand side of the range encompassing the output. Note that the last entry in the original range does not affect the output.

For example, the output of

  std::vector<int> u{ 2, 3, 2, 3, 1, 1, 2, 3, 5, 2 };
  std::cout << u << std::endl;

  std::vector<int> v( 10 );

  std::exclusive_scan( u.begin(), u.end(), v.begin(), 17 );
  std::cout << v << std::endl;

  std::exclusive_scan( u.begin(), u.end(), v.begin(), 17, std::multiplies<int>() );
  std::cout << v << std::endl;

is

{2, 3, 2, 3, 1, 1, 2, 3, 5, 2}
{17, 19, 22, 24, 27, 28, 29, 31, 34, 39}
{17, 34, 102, 204, 612, 612, 612, 1224, 3672, 18360}

itr_t std::adjacent_difference( itr_t itr_first, itr_t itr_last, itr_t itr_out )
itr_t std::adjacent_difference( itr_t itr_first, itr_t itr_last, itr_t itr_out, T minus( T, T ) )

Assuming that the input ranges are not empty, these copy the first entry of the input to the first entry of the output, and all subsequent entries of the output are the difference between the corresponding entry in the input range minus the previous entry in the input range.

These are equivalent to:

    // Assuming the range is not empty
    T last{ *itr_first };
    *itr_out = last;
    ++itr_first;

    while ( itr_first != itr_last ) {
      T next{ *itr_first };
      // First declaration
      *itr_out = next - last;
      // Second declaration
      // *itr_out = minus( next, last );
      last = next;

      ++itr_first;
      ++itr_out;
    }