Namespaces
Variants

std:: partial_sum

From cppreference.net
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy , ranges::sort , ...
Execution policies (C++17)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17) (C++11)
(C++20) (C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
Определено в заголовке <numeric>
template < class InputIt, class OutputIt >

OutputIt partial_sum ( InputIt first, InputIt last,

OutputIt d_first ) ;
(1) (constexpr начиная с C++20)
template < class InputIt, class OutputIt, class BinaryOp >

OutputIt partial_sum ( InputIt first, InputIt last,

OutputIt d_first, BinaryOp op ) ;
(2) (constexpr начиная с C++20)
1) Если [ first , last ) пуст, ничего не делает.
В противном случае выполняет следующие операции по порядку:
  1. Создает аккумулятор acc , чей тип соответствует value type для InputIt , и инициализирует его значением * first .
  2. Присваивает значение acc переменной * d_first .
  3. Для каждого целого числа i в диапазоне [ 1 , std:: distance ( first, last ) ) , выполняет следующие операции по порядку:
a) Вычисляет acc + * iter (до C++20) std :: move ( acc ) + * iter (начиная с C++20) , где iter является следующим i итератором first .
б) Присваивает результат переменной acc .
c) Присваивает acc [1] значению * dest , где dest является следующим i -ым итератором d_first .
2) То же, что и (1) , но вычисляет op ( acc, * iter ) (до C++20) op ( std :: move ( acc ) , * iter ) (начиная с C++20) вместо этого.

Дано binary_op как фактическую бинарную операцию:

  • Если выполняется любое из следующих условий, программа является некорректной:
  • Тип значения InputIt не конструируется из * first .
  • acc не является записываемым в d_first .
  • Результат binary_op ( acc, * iter ) (до C++20) binary_op ( std :: move ( acc ) , * iter ) (начиная с C++20) не является неявно преобразуемым к типу значения InputIt .
  • Пусть d_last является итератором, который должен быть возвращён . Если выполняется любое из следующих условий, поведение не определено:
  • binary_op изменяет любой элемент в [ first , last ) или [ d_first , d_last ) .
  • binary_op инвалидирует любой итератор или поддиапазон в [ first , last ] или [ d_first , d_last ] .


  1. Фактическое значение для присваивания является результатом присваивания на предыдущем шаге. Предполагаем, что результатом присваивания здесь является acc .

Содержание

Параметры

first, last - пара итераторов, определяющих диапазон элементов для суммирования
d_first - начало целевого диапазона; может быть равен first
op - функциональный объект бинарной операции, который будет применён.

Сигнатура функции должна быть эквивалентна следующей:

Ret fun ( const Type1 & a, const Type2 & b ) ;

Сигнатура не обязана содержать const & .
Тип Type1 должен быть таким, чтобы объект типа std:: iterator_traits < InputIt > :: value_type мог быть неявно преобразован в Type1 . Тип Type2 должен быть таким, чтобы объект типа InputIt мог быть разыменован и затем неявно преобразован в Type2 . Тип Ret должен быть таким, чтобы объект типа InputIt мог быть разыменован и ему присвоено значение типа Ret . ​

Требования к типам
-
InputIt должен удовлетворять требованиям LegacyInputIterator .
-
OutputIt должен удовлетворять требованиям LegacyOutputIterator .

Возвращаемое значение

Итератор на элемент, следующий за последним записанным элементом, или d_first если [ first , last ) является пустым.

Сложность

Дано N как std:: distance ( first, last ) :

1) Ровно N-1 применений operator + .
2) Ровно N-1 применений бинарной функции op .

Возможная реализация

partial_sum (1)
template<class InputIt, class OutputIt>
constexpr // since C++20
OutputIt partial_sum(InputIt first, InputIt last, OutputIt d_first)
{
    if (first == last)
        return d_first;
    typename std::iterator_traits<InputIt>::value_type sum = *first;
    *d_first = sum;
    while (++first != last)
    {
        sum = std::move(sum) + *first; // std::move since C++20
        *++d_first = sum;
    }
    return ++d_first;
    // или, начиная с C++14:
    // return std::partial_sum(first, last, d_first, std::plus<>());
}
partial_sum (2)
template<class InputIt, class OutputIt, class BinaryOp>
constexpr // since C++20
OutputIt partial_sum(InputIt first, InputIt last, 
                     OutputIt d_first, BinaryOp op)
{
    if (first == last)
        return d_first;
    typename std::iterator_traits<InputIt>::value_type acc = *first;
    *d_first = acc;
    while (++first != last)
    {
        acc = op(std::move(acc), *first); // std::move since C++20
        *++d_first = acc;
    }
    return ++d_first;
}

Примечания

acc был введен в результате решения проблемы LWG 539 . Причина использования acc вместо прямого суммирования результатов (т.е. * ( d_first + 2 ) = ( * first + * ( first + 1 ) ) + * ( first + 2 ) ; ) заключается в том, что семантика последнего становится неоднозначной при несоответствии следующих типов:

  • тип значения InputIt
  • записываемый тип(ы) OutputIt
  • типы параметров operator + или op
  • возвращаемый тип operator + или op

acc служит промежуточным объектом для хранения и предоставления значений на каждом шаге вычислений:

  • его тип - это тип значения InputIt
  • он записывается в d_first
  • его значение передается в operator + или op
  • он сохраняет возвращаемое значение operator + или op
enum not_int { x = 1, y = 2 };
char i_array[4] = {100, 100, 100, 100};
not_int e_array[4] = {x, x, y, y};
int  o_array[4];
// OK: использует operator+(char, char) и присваивает значения char массиву int
std::partial_sum(i_array, i_array + 4, o_array);
// Ошибка: невозможно присвоить значения not_int массиву int
std::partial_sum(e_array, e_array + 4, o_array);
// OK: выполняет преобразования при необходимости
// 1. создает "acc" типа char (тип значения)
// 2. аргументы char используются для умножения long (char -> long)
// 3. произведение long присваивается "acc" (long -> char)
// 4. "acc" присваивается элементу "o_array" (char -> int)
// 5. возврат к шагу 2 для обработки оставшихся элементов входного диапазона
std::partial_sum(i_array, i_array + 4, o_array, std::multiplies<long>{});

Пример

#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
    std::vector<int> v(10, 2); // v = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
    std::cout << "Первые " << v.size() << " четных числа: ";
    // записать результат в поток cout
    std::partial_sum(v.cbegin(), v.cend(), 
                     std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
    // записать результат обратно в вектор v
    std::partial_sum(v.cbegin(), v.cend(),
                     v.begin(), std::multiplies<int>());
    std::cout << "Первые " << v.size() << " степени двойки: ";
    for (int n : v)
        std::cout << n << ' ';
    std::cout << '\n';
}

Вывод:

Первые 10 четных чисел: 2 4 6 8 10 12 14 16 18 20 
Первые 10 степеней двойки: 2 4 8 16 32 64 128 256 512 1024

Отчёты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
LWG 242 C++98 op could not have side effects it cannot modify the ranges involved
LWG 539 C++98 the type requirements needed for the result
evaluations and assignments to be valid were missing
added

Смотрите также

вычисляет разности между соседними элементами в диапазоне
(шаблон функции)
суммирует или сворачивает диапазон элементов
(шаблон функции)
аналогично std::partial_sum , включает i й входной элемент в i ю сумму
(шаблон функции)
аналогично std::partial_sum , исключает i й входной элемент из i й суммы
(шаблон функции)