Стандартная библиотека C++<numeric>

В повседневной разработке на C++ мы часто сталкиваемся со следующими требованиями:

  • Вычислить сумму / произведение массива
  • Вычислить префиксные суммы для запросов по диапазону
  • Пакетное накопление для создания новой последовательности
  • Вычислить внутреннее произведение (скалярное произведение) между векторами

Если вы всё ещё пишете это вручнуюforЦикл, затем<numeric>Это именно те инструменты стандартной библиотеки, которыми вам следует овладеть.

В стандартной библиотеке C++<numeric>Заголовочный файл предоставляет набор шаблонов функций для численных вычислений. Эти функции могут выполнять различные численные операции над элементами контейнера, такие как суммирование, произведение, минимум, максимум и т. д. Эти шаблоны функций чрезвычайно мощны и могут применяться к любому типу контейнера, включая массивы, векторы, списки и так далее.

При использовании<numeric>Прежде чем использовать функции из заголовочного файла, вам нужно включить этот заголовочный файл в вашу программу на C++:

#include <numeric>

Общие функции

  • <numeric>так C++ обрабатываетвычисление числовых последовательностейЭто основной заголовочный файл, ориентированный на такие операции, как редукция, накопление и разность, и совместим со всеми контейнерами STL;
  • Базовые функции (accumulate/partial_sum/iotaЭто ядро C++98/11, удовлетворяющее большинству обычных потребностей в численных вычислениях;
  • добавлено в C++17reduce/inclusive_scanТакие параллельные функции могут значительно повысить эффективность вычислений при больших объёмах данных, и их нужно использовать с политиками параллельного выполнения.
Имя функции Версия C++ Основные функции Упрощённый прототип функции (взявvector<int>в качестве примера) типичные варианты использования
accumulate C++98 Вычисляет кумулятивную сумму последовательности (можно указать пользовательскую бинарную операцию) int accumulate(iterator beg, iterator end, int init); Вычисление суммы массива, накопление статистики
inner_product C++98 Вычисляет скалярное произведение двух последовательностей (перемножает соответствующие элементы и затем суммирует; можно указать пользовательские операции) int inner_product(iter1 b1, iter1 e1, iter2 b2, int init); Скалярное произведение векторов, взвешенная сумма
partial_sum C++98 Вычисляет префиксные суммы последовательности (n-й результат = сумма первых n элементов, настраиваемая операция) void partial_sum(iter b, iter e, iter res); Генерация массива префиксных сумм, накопление статистики
adjacent_difference C++98 Вычисляет разности между соседними элементами последовательности (n-й результат = elem[n] - elem[n-1], настраиваемая операция) void adjacent_difference(iter b, iter e, iter res); Вычисление разностей, обнаружение изменений последовательности
iota C++11 Заполняет последовательность непрерывно возрастающими значениями (начиная с init, увеличивая на 1 каждый раз) void iota(iter b, iter e, T init); Генерирует последовательность идущих подряд целых чисел, инициализирует упорядоченные контейнеры
reduce C++17 Параллельная версия accumulate (аналогично accumulate, поддерживает параллельное выполнение, неупорядоченная редукция) T reduce(iter b, iter e, T init = T{}); Параллельное суммирование для больших объёмов данных, повышающее вычислительную эффективность
transform_reduce C++17 Преобразование + редукция (сначала преобразуются элементы, затем выполняется накопление, поддерживается параллельное выполнение) T transform_reduce(iter1 b1, iter1 e1, iter2 b2, T init); Параллельное скалярное произведение, сумма после преобразования
inclusive_scan C++17 Параллельная префиксная сумма (включая текущий элемент, аналогично partial_sum, поддерживает параллельное выполнение) void inclusive_scan(iter b, iter e, iter res); Параллельная генерация массивов префиксных сумм
exclusive_scan C++17 Параллельная версия префиксной суммы (исключая текущий элемент; n-й результат = сумма первых n-1 элементов) void exclusive_scan(iter b, iter e, iter res, T init); Параллельная генерация префиксных сумм, не включающих текущий элемент

1. accumulate

accumulateФункция используется для вычисления суммы всех элементов в контейнере. Она принимает три параметра: начальный итератор контейнера, конечный итератор и начальное значение.

Синтаксис:

template <InputIterator Iter, class T>
T accumulate(Iter first, Iter last, T init);

Пример:

Пример

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

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5};
    int sum = std::accumulate(v.begin(), v.end(), 0);
    std::cout << "Сумма: " << sum << std::endl; // Вывод: Sum: 15
    return 0;
}

2. inner_product

inner_productФункция используется для вычисления суммы произведений соответствующих элементов в двух контейнерах.

Синтаксис:

template <InputIterator1 Iter1, InputIterator2 Iter2, class T>
T inner_product(Iter1 first1, Iter1 last1, Iter2 first2, T init);

Пример:

Пример

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

int main() {
    std::vector<int> v1 = {1, 2, 3};
    std::vector<int> v2 = {4, 5, 6};
    int product_sum = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);
    std::cout << "Product Sum: " << product_sum << std::endl; // Вывод: Product Sum: 32
    return 0;
}

3. partial_sum

partial_sumФункция вычисляет частичные суммы элементов контейнера и сохраняет результаты в другом контейнере.

Синтаксис:

template <InputIterator InIter, OutputIterator OutIter>
OutIter partial_sum(InIter first, InIter last, OutIter result);

Пример:

Пример

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

int main() {
    std::vector<int> v = {1, 2, 3, 4};
    std::vector<int> result(v.size());
    std::partial_sum(v.begin(), v.end(), result.begin());
    for (int i : result) {
        std::cout << i << " "; // Вывод: 1 3 6 10
    }
    return 0;
}

4. adjacent_difference

adjacent_differenceФункция вычисляет разности соседних элементов в контейнере и сохраняет результаты в другом контейнере.

Синтаксис:

template <InputIterator InIter, OutputIterator OutIter>
OutIter adjacent_difference(InIter first, InIter last, OutIter result);

Пример:

Пример

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

int main() {
    std::vector<int> v = {1, 2, 3, 4};
    std::vector<int> result(v.size() - 1);
    std::adjacent_difference(v.begin(), v.end(), result.begin());
    for (int i : result) {
        std::cout << i << " "; // Вывод: 1 1 1
    }
    return 0;
}

5. std::gcd

Используйте std::gcd для вычисления наибольшего общего делителя двух целых чисел:

Пример

#include <iostream>
#include <numeric>

int main() {
    int a = 48;
    int b = 18;
    int result = std::gcd(a, b);  // Вычислите наибольший общий делитель чисел 48 и 18
    std::cout << "GCD: " << result << std::endl;  // Вывод 6
    return 0;
}

6. std::lcm

Используйте std::lcm для вычисления наименьшего общего кратного двух целых чисел:

Пример

#include <iostream>
#include <numeric>

int main() {
    int a = 48;
    int b = 18;
    int result = std::lcm(a, b);  // Вычислите наименьшее общее кратное чисел 48 и 18
    std::cout << "LCM: " << result << std::endl;  // Вывод 144
    return 0;
}

7. std::iota

Пример

#include <iostream>
#include <numeric> // Подключение заголовочного файла numeric
#include <vector>

int main() {
    std::vector<int> v(5); // Создайте вектор, содержащий 5 элементов

    // Заполните вектор с помощью std::iota, начиная с 1
    std::iota(std::begin(v), std::end(v), 1);

    // Выведите заполненный вектор
    for (int i : v) {
        std::cout << i << " ";
    }
    std::cout << std::endl; // Вывод: 1 2 3 4 5

    return 0;
}

Используйте std::iota для заполнения диапазона последовательными значениями.

template<class ForwardIt, class T>
void iota(ForwardIt first, ForwardIt last, T value);

8. Поиск максимального и минимального значений

min_elementиmax_elementФункция используется для поиска максимального и минимального значений в контейнере.

Пример

#include <iostream>
#include <numeric>
#include <vector>
#include <algorithm> // Для использования std::min_element и std::max_element

int main() {
    // Определите вектор целых чисел
    std::vector<int> v = {3, 1, 4, 1, 5, 9};

    // Вычислить минимальное и максимальное значения
    int min_val = *std::min_element(v.begin(), v.end());
    int max_val = *std::max_element(v.begin(), v.end());

    // Вычислить сумму
    int sum_val = std::accumulate(v.begin(), v.end(), 0);

    // Вычислить среднее значение
    double avg_val = static_cast<double>(sum_val) / v.size();

    // Вывод результатов
    std::cout << "Минимум: " << min_val << std::endl;
    std::cout << "Максимум: " << max_val << std::endl;
    std::cout << "Сумма: " << sum_val << std::endl;
    std::cout << "Среднее: " << avg_val << std::endl;

    return 0;
}

Результат вывода:

Min: 1
Max: 9
Sum: 23
Average: 3.83333
Другие расширения