<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Bannikov+Nikolay</id>
	<title>Алговики - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Bannikov+Nikolay"/>
	<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/ru/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Bannikov_Nikolay"/>
	<updated>2026-10-22T15:38:41Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30298</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30298"/>
		<updated>2025-12-09T00:24:40Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{level-a}}&lt;br /&gt;
&lt;br /&gt;
{{algorithm&lt;br /&gt;
| name              = Параллельный алгоритм вычисления всех частных сумм&lt;br /&gt;
| serial_complexity = &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_height         = &amp;lt;math&amp;gt;\log_{2} n&amp;lt;/math&amp;gt;&lt;br /&gt;
| pf_width          = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
| input_data        = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
| output_data       = &amp;lt;math&amp;gt;n&amp;lt;/math&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Основные авторы описания: [[Участник:Bannikov Nikolay|Н.В.Банников]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления всех частных сумм массива порядка &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; с помощью алгоритма в его параллельном варианте требуется выполнить  &amp;lt;math&amp;gt; (\log_{2} n)&amp;lt;/math&amp;gt; ярусов с убывающим параллелизмом: от &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; операции суммирования на ярус. &lt;br /&gt;
В предположении доступности неограниченного числа необходимых процессоров  требуется &amp;lt;math&amp;gt; O(n \log n)&amp;lt;/math&amp;gt; операций при &amp;lt;math&amp;gt; p = n &amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt; времени. При классификации по  высоте ЯПФ алгоритм имеет логарифмическую высоту &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt;,а при классификации по ширине ЯПФ алгоритм имеет линейную ширину ярусов &amp;lt;math&amp;gt; O(n)&amp;lt;/math&amp;gt;, реализуя массовый координатный параллелизм по индексу процессорных элементов.&lt;br /&gt;
Максимальное ускорение ограничено &amp;lt;math&amp;gt; O(\frac{n}{\log n})&amp;lt;/math&amp;gt; из закона Амдала. &lt;br /&gt;
Наиболее эффективен при &amp;lt;math&amp;gt;n ≫ p ≥ \log n&amp;lt;/math&amp;gt;. Поскольку эффективность алгоритма уменьшается при росте &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; и составляет &amp;lt;math&amp;gt; O(\frac{1}{\log n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: Массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Формула: &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые особенности&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Вход и выход одинакового размера и типа&lt;br /&gt;
# Минимум &amp;lt;math&amp;gt; 2n &amp;lt;/math&amp;gt; элементов памяти (вход + выход)&lt;br /&gt;
# Можно перезаписать входной массив с целью экономии памяти&lt;br /&gt;
# Последний элемент &amp;lt;math&amp;gt; s_n &amp;lt;/math&amp;gt; содержит сумму всех входных чисел&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Переполнение: Риск для целых чисел при больших &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Точность: Накопление ошибок для чисел с плавающей точкой&lt;br /&gt;
* Память: Максимальный &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ограничен доступной памятью&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в предположении доступности неограниченного числа необходимых процессоров, является &amp;lt;math&amp;gt; \frac{n}{\log_{2} n}&amp;lt;/math&amp;gt; отношение линейной к логарифмической, ограничено законом Амдала. &lt;br /&gt;
Алгоритм дает существенное теоретическое ускорение, почти линейное с эффективностью &amp;lt;math&amp;gt; \frac{1}{\log_{2} n}&amp;lt;/math&amp;gt;.&lt;br /&gt;
При этом вычислительная мощность алгоритма, как отношение числа арифметических операций к суммарному объему входных и выходных данных растет как &amp;lt;math&amp;gt; \log n&amp;lt;/math&amp;gt;: при больших &amp;lt;math&amp;gt; n&amp;lt;/math&amp;gt; на один элемент данных приходится все больше операций. Это положительный момент для реализации на ускорителях и сопроцессорах: накладные расходы на пересылку данных относительно стоимости вычислений снижаются.&lt;br /&gt;
Для целых чисел алгоритм абсолютно устойчив, получаем точный результат при отсутствии переполнения. Для чисел с плавающей точкой условно устойчив, поскольку накапливается ошибка округления, где погрешность &amp;lt;math&amp;gt; O(n · ε)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; ε &amp;lt;/math&amp;gt; - машинная точность.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм сбалансирован, поскольку лишь одна операция сложения, нет умножений/делений и.т.д. Алгоритм полностью детерминирован, поскольку число этапов фиксировано и равно &amp;lt;math&amp;gt; \log_{2} n&amp;lt;/math&amp;gt;, набор операций, выполняемых каждым ПЭ на каждом этапе заранее известен и не зависит от входных данных, отсутствуют ветвления по данным, циклы с выходом по точности, использование случайных чисел и.т.п.&amp;lt;br&amp;gt;&lt;br /&gt;
В алгоритме нет «массовых рассылок» скалярных величин с большой степенью исхода одной вершины. Это снижает требования к механизмам широковещательной передачи и упрощает эффективный доступ к данным: каждый результат либо остаётся локальным, либо передаётся ограниченному числу соседей по коммуникационной схеме.&amp;lt;br&amp;gt;&lt;br /&gt;
В линейной системе координат присутствуют длинные дуги, что требует аккуратного отображения на реальную топологию, но при подходящем выборе топологии эти дуги становятся локальными.&amp;lt;br&amp;gt;&lt;br /&gt;
Граф алгоритма регулярно устроен и допускает компактные укладки и конвейеризацию при реализации на специализированных архитектурах.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
===  Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Стандартная последовательная реализация использует простую рекуррентную формулу: каждая следующая частичная сумма вычисляется как сумма предыдущей частичной суммы и текущего элемента массива. Это естественное решение с линейной сложностью &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt;, где выполняется ровно &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; операций сложения. Реализация сталкивается с фундаментальным выбором: сохранять исходные данные, создавая отдельный массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, тем самым увеличивая использование памяти в 2 раза, либо перезаписывать исходный массив, что позволяет экономить память, однако безвозвратно уничтожает входные данные. Такой выбор критичен при работе с большими массивами, где объем памяти становится ограничивающим фактором. &amp;lt;br&amp;gt;&lt;br /&gt;
Для массивов, превышающих размер кэш-памяти процессора, применяется блочная стратегия. Массив разбивается на блоки размером M, где M выбирается таким образом, чтобы блок полностью помещался в кэш L1 или L2. Типичные значения M составляют 16-64 тысяч элементов для 32-битных чисел. Внутри каждого блока последовательно считаются частичные суммы, для блоков хранятся их полные суммы. При переходе к следующему блоку к его элементам добавляется накопленная сумма всех предыдущих блоков. Это улучшает работу с кэш-памятью и даёт удобную основу для параллельных версий. &amp;lt;br&amp;gt;&lt;br /&gt;
Говоря про разрядность, часто нет необходимости выполнять все операции в double. На практике разумен вариант: элементы хранятся в float, а накопитель суммы — в double. Это уменьшает ошибки округления при небольших накладных расходах. Для целых данных следует выбирать достаточно широкий тип (обычно 64-битный), чтобы избежать переполнения.&amp;lt;br&amp;gt;&lt;br /&gt;
Ресурс параллелизма непосредственно в линейном цикле ограничен (каждая итерация зависит от предыдущей), но за счёт ассоциативности сложения алгоритм можно эквивалентно преобразовать в блочную или другие формы. Такие формы удобны для распараллеливания и реализации на многоядерных системах и кластерах. Векторизация ограничена зависимостью между итерациями, но эффективность улучшается за счёт выравнивания данных, линейного доступа и использования более узких типов (float).&lt;br /&gt;
С точки зрения различных платформ:&lt;br /&gt;
* на &#039;&#039;&#039;многоядерных SMP-узлах&#039;&#039;&#039; блоки естественно распределяются по потокам&lt;br /&gt;
* на &#039;&#039;&#039;векторных и GPU-архитектурах&#039;&#039;&#039; используются деревообразные формы&lt;br /&gt;
* на &#039;&#039;&#039;кластерах&#039;&#039;&#039; частичные суммы считаются локально с последующей глобальной коррекцией&lt;br /&gt;
&lt;br /&gt;
===  Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ввиду слабой распространённости задачи нахождения частных сумм в библиотеках данный алгоритм обычно не содержится. &amp;lt;br&amp;gt;&lt;br /&gt;
Для алгоритма вычисления всех частичных сумм по одномерному массиву естественно использовать иерархический ресурс параллелизма.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Иерархия параллелизма:&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Векторный уровень (SIMD)&#039;&#039;&#039;&lt;br /&gt;
Внутри одного потока данные обрабатываются блоками, для которых сначала вычисляются локальные суммы, затем выполняется локальный префикс внутри блока. Это даёт массовый параллелизм на уровне регистров.&lt;br /&gt;
* &#039;&#039;&#039;Уровень нитей / потоков (OpenMP)&#039;&#039;&#039;&lt;br /&gt;
Массив делится на &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; непрерывных сегментов. Каждый поток считает локальные частичные суммы внутри своего сегмента, затем формируется массив из сумм сегментов длины &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt;. По этому массиву выполняется префиксная сумма (последовательно или параллельно). Полученные &amp;quot;смещения&amp;quot; добавляются ко всем элементам соответствующих сегментов. &amp;lt;br&amp;gt;&lt;br /&gt;
Количество операций: примерно &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt; арифметики + &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; для обработки сумм сегментов на потоках. &amp;lt;br&amp;gt;&lt;br /&gt;
Объем дополнительных данных - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Уровень процессов (MPI, кластеры)&#039;&#039;&#039;&lt;br /&gt;
Аналогично нитям ,каждый MPI-процесс хранит свой участок массива (распределение по непрерывным блокам), локально считает частичные суммы. Далее выполняется коллективная операция MPI_Scan или эквивалентная схема с MPI_Allgather/MPI_Bcast для префиксной суммы по суммам процессов. Процессы добавляют своё смещение ко всем локальным элементам.&lt;br /&gt;
Объем коммуникаций: по суммам процессов - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; чисел (обычно одно-два double/int64 на процесс), число шагов ~ &amp;lt;math&amp;gt; O(\log P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Распределение операций и данных:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данные удобно распределять по непрерывным блокам (по индексам), что минимизирует пересылки, обеспечивает линейный доступ к памяти, упрощает векторизацию. Операции в основном локальны: суммирование внутри сегмента. Глобальная часть — это только обработка сумм сегментов/процессов (малый объём).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Оценка сложности:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для массива длины &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;, при &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; параллельных единицах (нити/процессы):&lt;br /&gt;
* &#039;&#039;&#039;Локальные операции:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; \frac{N}{P} &amp;lt;/math&amp;gt; сложений на каждую нить/процесс&lt;br /&gt;
* &#039;&#039;&#039;Глобальные операции по суммам блоков:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; сложений в сумме, либо &amp;lt;math&amp;gt; \log P &amp;lt;/math&amp;gt; шагов в дереве&lt;br /&gt;
* &#039;&#039;&#039;Объем пересылок (MPI)&#039;&#039;&#039;: один-два числа на процесс, не зависящий от &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, вычислительная сложность остаётся &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt;, а масштабируемость в основном ограничивается коммуникацией по &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; и пропускной способностью памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Использование конкретных технологий:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Параллельная реализация алгоритма частичных сумм строится как двух–трёхступенчатое сканирование: локальное (внутри блока/процесса), глобальное по блокам/процессам и последующая корректировка, что одинаково хорошо ложится на модели OpenMP, MPI, CUDA и схемы векторизации.&lt;br /&gt;
&lt;br /&gt;
===  Результаты прогонов ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм реализовывался с помощью технологии параллельного программирования MPI, запускался на суперкомпьютере &amp;quot;Ломоносов-2&amp;quot;.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|-&lt;br /&gt;
! Количество MPI-процессов(p) !! T !! S(p) !! E(p)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0,00001 || 1 || 1&lt;br /&gt;
|-&lt;br /&gt;
| 2 || 0,0000253 || 0,395 || 0,198&lt;br /&gt;
|-&lt;br /&gt;
| 4 || 0,0000273 || 0,366 || 0,092&lt;br /&gt;
|-&lt;br /&gt;
| 8 || 0,0000396 || 0,250 || 0,032&lt;br /&gt;
|-&lt;br /&gt;
| 16 || 0,0001 || 0,010 || 0,00063&lt;br /&gt;
|-&lt;br /&gt;
| 32 || 0,000224 || 0,045 || 0,0014&lt;br /&gt;
|-&lt;br /&gt;
| 64|| 0,000216 || 0,046 || 0,00072&lt;br /&gt;
|-&lt;br /&gt;
| 128 || 0,000227 || 0,044 || 0,000344&lt;br /&gt;
|-&lt;br /&gt;
| 256 || 0,000102 || 0,098 || 0,000382&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===  Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
В целом, для алгоритма частичных сумм на всех архитектурах ключевой фактор — организация памяти (линейный доступ, блочная/локальная работа, минимизация пересылок). Конкретные технологии (OpenMP, MPI, CUDA, директивы SIMD) в основном «оборачивают» одну и ту же двух–трёхэтапную схему: локальное сканирование, префикс по агрегированным суммам и корректировка результатов.&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30296</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30296"/>
		<updated>2025-12-09T00:17:07Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления всех частных сумм массива порядка &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; с помощью алгоритма в его параллельном варианте требуется выполнить  &amp;lt;math&amp;gt; (\log_{2} n)&amp;lt;/math&amp;gt; ярусов с убывающим параллелизмом: от &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; операции суммирования на ярус. &lt;br /&gt;
В предположении доступности неограниченного числа необходимых процессоров  требуется &amp;lt;math&amp;gt; O(n \log n)&amp;lt;/math&amp;gt; операций при &amp;lt;math&amp;gt; p = n &amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt; времени. При классификации по  высоте ЯПФ алгоритм имеет логарифмическую высоту &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt;,а при классификации по ширине ЯПФ алгоритм имеет линейную ширину ярусов &amp;lt;math&amp;gt; O(n)&amp;lt;/math&amp;gt;, реализуя массовый координатный параллелизм по индексу процессорных элементов.&lt;br /&gt;
Максимальное ускорение ограничено &amp;lt;math&amp;gt; O(\frac{n}{\log n})&amp;lt;/math&amp;gt; из закона Амдала. &lt;br /&gt;
Наиболее эффективен при &amp;lt;math&amp;gt;n ≫ p ≥ \log n&amp;lt;/math&amp;gt;. Поскольку эффективность алгоритма уменьшается при росте &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; и составляет &amp;lt;math&amp;gt; O(\frac{1}{\log n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: Массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Формула: &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые особенности&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Вход и выход одинакового размера и типа&lt;br /&gt;
# Минимум &amp;lt;math&amp;gt; 2n &amp;lt;/math&amp;gt; элементов памяти (вход + выход)&lt;br /&gt;
# Можно перезаписать входной массив с целью экономии памяти&lt;br /&gt;
# Последний элемент &amp;lt;math&amp;gt; s_n &amp;lt;/math&amp;gt; содержит сумму всех входных чисел&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Переполнение: Риск для целых чисел при больших &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Точность: Накопление ошибок для чисел с плавающей точкой&lt;br /&gt;
* Память: Максимальный &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ограничен доступной памятью&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в предположении доступности неограниченного числа необходимых процессоров, является &amp;lt;math&amp;gt; \frac{n}{\log_{2} n}&amp;lt;/math&amp;gt; отношение линейной к логарифмической, ограничено законом Амдала. &lt;br /&gt;
Алгоритм дает существенное теоретическое ускорение, почти линейное с эффективностью &amp;lt;math&amp;gt; \frac{1}{\log_{2} n}&amp;lt;/math&amp;gt;.&lt;br /&gt;
При этом вычислительная мощность алгоритма, как отношение числа арифметических операций к суммарному объему входных и выходных данных растет как &amp;lt;math&amp;gt; \log n&amp;lt;/math&amp;gt;: при больших &amp;lt;math&amp;gt; n&amp;lt;/math&amp;gt; на один элемент данных приходится все больше операций. Это положительный момент для реализации на ускорителях и сопроцессорах: накладные расходы на пересылку данных относительно стоимости вычислений снижаются.&lt;br /&gt;
Для целых чисел алгоритм абсолютно устойчив, получаем точный результат при отсутствии переполнения. Для чисел с плавающей точкой условно устойчив, поскольку накапливается ошибка округления, где погрешность &amp;lt;math&amp;gt; O(n · ε)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; ε &amp;lt;/math&amp;gt; - машинная точность.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм сбалансирован, поскольку лишь одна операция сложения, нет умножений/делений и.т.д. Алгоритм полностью детерминирован, поскольку число этапов фиксировано и равно &amp;lt;math&amp;gt; \log_{2} n&amp;lt;/math&amp;gt;, набор операций, выполняемых каждым ПЭ на каждом этапе заранее известен и не зависит от входных данных, отсутствуют ветвления по данным, циклы с выходом по точности, использование случайных чисел и.т.п.&amp;lt;br&amp;gt;&lt;br /&gt;
В алгоритме нет «массовых рассылок» скалярных величин с большой степенью исхода одной вершины. Это снижает требования к механизмам широковещательной передачи и упрощает эффективный доступ к данным: каждый результат либо остаётся локальным, либо передаётся ограниченному числу соседей по коммуникационной схеме.&amp;lt;br&amp;gt;&lt;br /&gt;
В линейной системе координат присутствуют длинные дуги, что требует аккуратного отображения на реальную топологию, но при подходящем выборе топологии эти дуги становятся локальными.&amp;lt;br&amp;gt;&lt;br /&gt;
Граф алгоритма регулярно устроен и допускает компактные укладки и конвейеризацию при реализации на специализированных архитектурах.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
===  Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Стандартная последовательная реализация использует простую рекуррентную формулу: каждая следующая частичная сумма вычисляется как сумма предыдущей частичной суммы и текущего элемента массива. Это естественное решение с линейной сложностью &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt;, где выполняется ровно &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; операций сложения. Реализация сталкивается с фундаментальным выбором: сохранять исходные данные, создавая отдельный массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, тем самым увеличивая использование памяти в 2 раза, либо перезаписывать исходный массив, что позволяет экономить память, однако безвозвратно уничтожает входные данные. Такой выбор критичен при работе с большими массивами, где объем памяти становится ограничивающим фактором. &amp;lt;br&amp;gt;&lt;br /&gt;
Для массивов, превышающих размер кэш-памяти процессора, применяется блочная стратегия. Массив разбивается на блоки размером M, где M выбирается таким образом, чтобы блок полностью помещался в кэш L1 или L2. Типичные значения M составляют 16-64 тысяч элементов для 32-битных чисел. Внутри каждого блока последовательно считаются частичные суммы, для блоков хранятся их полные суммы. При переходе к следующему блоку к его элементам добавляется накопленная сумма всех предыдущих блоков. Это улучшает работу с кэш-памятью и даёт удобную основу для параллельных версий. &amp;lt;br&amp;gt;&lt;br /&gt;
Говоря про разрядность, часто нет необходимости выполнять все операции в double. На практике разумен вариант: элементы хранятся в float, а накопитель суммы — в double. Это уменьшает ошибки округления при небольших накладных расходах. Для целых данных следует выбирать достаточно широкий тип (обычно 64-битный), чтобы избежать переполнения.&amp;lt;br&amp;gt;&lt;br /&gt;
Ресурс параллелизма непосредственно в линейном цикле ограничен (каждая итерация зависит от предыдущей), но за счёт ассоциативности сложения алгоритм можно эквивалентно преобразовать в блочную или другие формы. Такие формы удобны для распараллеливания и реализации на многоядерных системах и кластерах. Векторизация ограничена зависимостью между итерациями, но эффективность улучшается за счёт выравнивания данных, линейного доступа и использования более узких типов (float).&lt;br /&gt;
С точки зрения различных платформ:&lt;br /&gt;
* на &#039;&#039;&#039;многоядерных SMP-узлах&#039;&#039;&#039; блоки естественно распределяются по потокам&lt;br /&gt;
* на &#039;&#039;&#039;векторных и GPU-архитектурах&#039;&#039;&#039; используются деревообразные формы&lt;br /&gt;
* на &#039;&#039;&#039;кластерах&#039;&#039;&#039; частичные суммы считаются локально с последующей глобальной коррекцией&lt;br /&gt;
&lt;br /&gt;
===  Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ввиду слабой распространённости задачи нахождения частных сумм в библиотеках данный алгоритм обычно не содержится. &amp;lt;br&amp;gt;&lt;br /&gt;
Для алгоритма вычисления всех частичных сумм по одномерному массиву естественно использовать иерархический ресурс параллелизма.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Иерархия параллелизма:&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Векторный уровень (SIMD)&#039;&#039;&#039;&lt;br /&gt;
Внутри одного потока данные обрабатываются блоками, для которых сначала вычисляются локальные суммы, затем выполняется локальный префикс внутри блока. Это даёт массовый параллелизм на уровне регистров.&lt;br /&gt;
* &#039;&#039;&#039;Уровень нитей / потоков (OpenMP)&#039;&#039;&#039;&lt;br /&gt;
Массив делится на &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; непрерывных сегментов. Каждый поток считает локальные частичные суммы внутри своего сегмента, затем формируется массив из сумм сегментов длины &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt;. По этому массиву выполняется префиксная сумма (последовательно или параллельно). Полученные &amp;quot;смещения&amp;quot; добавляются ко всем элементам соответствующих сегментов. &amp;lt;br&amp;gt;&lt;br /&gt;
Количество операций: примерно &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt; арифметики + &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; для обработки сумм сегментов на потоках. &amp;lt;br&amp;gt;&lt;br /&gt;
Объем дополнительных данных - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Уровень процессов (MPI, кластеры)&#039;&#039;&#039;&lt;br /&gt;
Аналогично нитям ,каждый MPI-процесс хранит свой участок массива (распределение по непрерывным блокам), локально считает частичные суммы. Далее выполняется коллективная операция MPI_Scan или эквивалентная схема с MPI_Allgather/MPI_Bcast для префиксной суммы по суммам процессов. Процессы добавляют своё смещение ко всем локальным элементам.&lt;br /&gt;
Объем коммуникаций: по суммам процессов - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; чисел (обычно одно-два double/int64 на процесс), число шагов ~ &amp;lt;math&amp;gt; O(\log P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Распределение операций и данных:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данные удобно распределять по непрерывным блокам (по индексам), что минимизирует пересылки, обеспечивает линейный доступ к памяти, упрощает векторизацию. Операции в основном локальны: суммирование внутри сегмента. Глобальная часть — это только обработка сумм сегментов/процессов (малый объём).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Оценка сложности:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для массива длины &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;, при &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; параллельных единицах (нити/процессы):&lt;br /&gt;
* &#039;&#039;&#039;Локальные операции:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; \frac{N}{P} &amp;lt;/math&amp;gt; сложений на каждую нить/процесс&lt;br /&gt;
* &#039;&#039;&#039;Глобальные операции по суммам блоков:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; сложений в сумме, либо &amp;lt;math&amp;gt; \log P &amp;lt;/math&amp;gt; шагов в дереве&lt;br /&gt;
* &#039;&#039;&#039;Объем пересылок (MPI)&#039;&#039;&#039;: один-два числа на процесс, не зависящий от &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, вычислительная сложность остаётся &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt;, а масштабируемость в основном ограничивается коммуникацией по &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; и пропускной способностью памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Использование конкретных технологий:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Параллельная реализация алгоритма частичных сумм строится как двух–трёхступенчатое сканирование: локальное (внутри блока/процесса), глобальное по блокам/процессам и последующая корректировка, что одинаково хорошо ложится на модели OpenMP, MPI, CUDA и схемы векторизации.&lt;br /&gt;
&lt;br /&gt;
===  Результаты прогонов ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм реализовывался с помощью технологии параллельного программирования MPI, запускался на суперкомпьютере &amp;quot;Ломоносов-2&amp;quot;.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
|-&lt;br /&gt;
! Количество MPI-процессов(p) !! T !! S(p) !! E(p)&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 0,00001 || 1 || 1&lt;br /&gt;
|-&lt;br /&gt;
| 2 || 0,0000253 || 0,395 || 0,198&lt;br /&gt;
|-&lt;br /&gt;
| 4 || 0,0000273 || 0,366 || 0,092&lt;br /&gt;
|-&lt;br /&gt;
| 8 || 0,0000396 || 0,250 || 0,032&lt;br /&gt;
|-&lt;br /&gt;
| 16 || 0,0001 || 0,010 || 0,00063&lt;br /&gt;
|-&lt;br /&gt;
| 32 || 0,000224 || 0,045 || 0,0014&lt;br /&gt;
|-&lt;br /&gt;
| 64|| 0,000216 || 0,046 || 0,00072&lt;br /&gt;
|-&lt;br /&gt;
| 128 || 0,000227 || 0,044 || 0,000344&lt;br /&gt;
|-&lt;br /&gt;
| 256 || 0,000102 || 0,098 || 0,000382&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===  Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
В целом, для алгоритма частичных сумм на всех архитектурах ключевой фактор — организация памяти (линейный доступ, блочная/локальная работа, минимизация пересылок). Конкретные технологии (OpenMP, MPI, CUDA, директивы SIMD) в основном «оборачивают» одну и ту же двух–трёхэтапную схему: локальное сканирование, префикс по агрегированным суммам и корректировка результатов.&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30212</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30212"/>
		<updated>2025-12-07T23:14:15Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления всех частных сумм массива порядка &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; с помощью алгоритма в его параллельном варианте требуется выполнить  &amp;lt;math&amp;gt; (\log_{2} n)&amp;lt;/math&amp;gt; ярусов с убывающим параллелизмом: от &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; операции суммирования на ярус. &lt;br /&gt;
В предположении доступности неограниченного числа необходимых процессоров  требуется &amp;lt;math&amp;gt; O(n \log n)&amp;lt;/math&amp;gt; операций при &amp;lt;math&amp;gt; p = n &amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt; времени. При классификации по  высоте ЯПФ алгоритм имеет логарифмическую высоту &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt;,а при классификации по ширине ЯПФ алгоритм имеет линейную ширину ярусов &amp;lt;math&amp;gt; O(n)&amp;lt;/math&amp;gt;, реализуя массовый координатный параллелизм по индексу процессорных элементов.&lt;br /&gt;
Максимальное ускорение ограничено &amp;lt;math&amp;gt; O(\frac{n}{\log n})&amp;lt;/math&amp;gt; из закона Амдала. &lt;br /&gt;
Наиболее эффективен при &amp;lt;math&amp;gt;n ≫ p ≥ \log n&amp;lt;/math&amp;gt;. Поскольку эффективность алгоритма уменьшается при росте &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; и составляет &amp;lt;math&amp;gt; O(\frac{1}{\log n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: Массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Формула: &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые особенности&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Вход и выход одинакового размера и типа&lt;br /&gt;
# Минимум &amp;lt;math&amp;gt; 2n &amp;lt;/math&amp;gt; элементов памяти (вход + выход)&lt;br /&gt;
# Можно перезаписать входной массив с целью экономии памяти&lt;br /&gt;
# Последний элемент &amp;lt;math&amp;gt; s_n &amp;lt;/math&amp;gt; содержит сумму всех входных чисел&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Переполнение: Риск для целых чисел при больших &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Точность: Накопление ошибок для чисел с плавающей точкой&lt;br /&gt;
* Память: Максимальный &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ограничен доступной памятью&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в предположении доступности неограниченного числа необходимых процессоров, является &amp;lt;math&amp;gt; \frac{n}{\log_{2} n}&amp;lt;/math&amp;gt; отношение линейной к логарифмической, ограничено законом Амдала. &lt;br /&gt;
Алгоритм дает существенное теоретическое ускорение, почти линейное с эффективностью &amp;lt;math&amp;gt; \frac{1}{\log_{2} n}&amp;lt;/math&amp;gt;.&lt;br /&gt;
При этом вычислительная мощность алгоритма, как отношение числа арифметических операций к суммарному объему входных и выходных данных растет как &amp;lt;math&amp;gt; \log n&amp;lt;/math&amp;gt;: при больших &amp;lt;math&amp;gt; n&amp;lt;/math&amp;gt; на один элемент данных приходится все больше операций. Это положительный момент для реализации на ускорителях и сопроцессорах: накладные расходы на пересылку данных относительно стоимости вычислений снижаются.&lt;br /&gt;
Для целых чисел алгоритм абсолютно устойчив, получаем точный результат при отсутствии переполнения. Для чисел с плавающей точкой условно устойчив, поскольку накапливается ошибка округления, где погрешность &amp;lt;math&amp;gt; O(n · ε)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; ε &amp;lt;/math&amp;gt; - машинная точность.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм сбалансирован, поскольку лишь одна операция сложения, нет умножений/делений и.т.д. Алгоритм полностью детерминирован, поскольку число этапов фиксировано и равно &amp;lt;math&amp;gt; \log_{2} n&amp;lt;/math&amp;gt;, набор операций, выполняемых каждым ПЭ на каждом этапе заранее известен и не зависит от входных данных, отсутствуют ветвления по данным, циклы с выходом по точности, использование случайных чисел и.т.п.&amp;lt;br&amp;gt;&lt;br /&gt;
В алгоритме нет «массовых рассылок» скалярных величин с большой степенью исхода одной вершины. Это снижает требования к механизмам широковещательной передачи и упрощает эффективный доступ к данным: каждый результат либо остаётся локальным, либо передаётся ограниченному числу соседей по коммуникационной схеме.&amp;lt;br&amp;gt;&lt;br /&gt;
В линейной системе координат присутствуют длинные дуги, что требует аккуратного отображения на реальную топологию, но при подходящем выборе топологии эти дуги становятся локальными.&amp;lt;br&amp;gt;&lt;br /&gt;
Граф алгоритма регулярно устроен и допускает компактные укладки и конвейеризацию при реализации на специализированных архитектурах.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
===  Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Стандартная последовательная реализация использует простую рекуррентную формулу: каждая следующая частичная сумма вычисляется как сумма предыдущей частичной суммы и текущего элемента массива. Это естественное решение с линейной сложностью &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt;, где выполняется ровно &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; операций сложения. Реализация сталкивается с фундаментальным выбором: сохранять исходные данные, создавая отдельный массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, тем самым увеличивая использование памяти в 2 раза, либо перезаписывать исходный массив, что позволяет экономить память, однако безвозвратно уничтожает входные данные. Такой выбор критичен при работе с большими массивами, где объем памяти становится ограничивающим фактором. &amp;lt;br&amp;gt;&lt;br /&gt;
Для массивов, превышающих размер кэш-памяти процессора, применяется блочная стратегия. Массив разбивается на блоки размером M, где M выбирается таким образом, чтобы блок полностью помещался в кэш L1 или L2. Типичные значения M составляют 16-64 тысяч элементов для 32-битных чисел. Внутри каждого блока последовательно считаются частичные суммы, для блоков хранятся их полные суммы. При переходе к следующему блоку к его элементам добавляется накопленная сумма всех предыдущих блоков. Это улучшает работу с кэш-памятью и даёт удобную основу для параллельных версий. &amp;lt;br&amp;gt;&lt;br /&gt;
Говоря про разрядность, часто нет необходимости выполнять все операции в double. На практике разумен вариант: элементы хранятся в float, а накопитель суммы — в double. Это уменьшает ошибки округления при небольших накладных расходах. Для целых данных следует выбирать достаточно широкий тип (обычно 64-битный), чтобы избежать переполнения.&amp;lt;br&amp;gt;&lt;br /&gt;
Ресурс параллелизма непосредственно в линейном цикле ограничен (каждая итерация зависит от предыдущей), но за счёт ассоциативности сложения алгоритм можно эквивалентно преобразовать в блочную или другие формы. Такие формы удобны для распараллеливания и реализации на многоядерных системах и кластерах. Векторизация ограничена зависимостью между итерациями, но эффективность улучшается за счёт выравнивания данных, линейного доступа и использования более узких типов (float).&lt;br /&gt;
С точки зрения различных платформ:&lt;br /&gt;
* на &#039;&#039;&#039;многоядерных SMP-узлах&#039;&#039;&#039; блоки естественно распределяются по потокам&lt;br /&gt;
* на &#039;&#039;&#039;векторных и GPU-архитектурах&#039;&#039;&#039; используются деревообразные формы&lt;br /&gt;
* на &#039;&#039;&#039;кластерах&#039;&#039;&#039; частичные суммы считаются локально с последующей глобальной коррекцией&lt;br /&gt;
&lt;br /&gt;
===  Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ввиду слабой распространённости задачи нахождения частных сумм в библиотеках данный алгоритм обычно не содержится. &amp;lt;br&amp;gt;&lt;br /&gt;
Для алгоритма вычисления всех частичных сумм по одномерному массиву естественно использовать иерархический ресурс параллелизма.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Иерархия параллелизма:&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Векторный уровень (SIMD)&#039;&#039;&#039;&lt;br /&gt;
Внутри одного потока данные обрабатываются блоками, для которых сначала вычисляются локальные суммы, затем выполняется локальный префикс внутри блока. Это даёт массовый параллелизм на уровне регистров.&lt;br /&gt;
* &#039;&#039;&#039;Уровень нитей / потоков (OpenMP)&#039;&#039;&#039;&lt;br /&gt;
Массив делится на &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; непрерывных сегментов. Каждый поток считает локальные частичные суммы внутри своего сегмента, затем формируется массив из сумм сегментов длины &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt;. По этому массиву выполняется префиксная сумма (последовательно или параллельно). Полученные &amp;quot;смещения&amp;quot; добавляются ко всем элементам соответствующих сегментов. &amp;lt;br&amp;gt;&lt;br /&gt;
Количество операций: примерно &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt; арифметики + &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; для обработки сумм сегментов на потоках. &amp;lt;br&amp;gt;&lt;br /&gt;
Объем дополнительных данных - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Уровень процессов (MPI, кластеры)&#039;&#039;&#039;&lt;br /&gt;
Аналогично нитям ,каждый MPI-процесс хранит свой участок массива (распределение по непрерывным блокам), локально считает частичные суммы. Далее выполняется коллективная операция MPI_Scan или эквивалентная схема с MPI_Allgather/MPI_Bcast для префиксной суммы по суммам процессов. Процессы добавляют своё смещение ко всем локальным элементам.&lt;br /&gt;
Объем коммуникаций: по суммам процессов - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; чисел (обычно одно-два double/int64 на процесс), число шагов ~ &amp;lt;math&amp;gt; O(\log P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Распределение операций и данных:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данные удобно распределять по непрерывным блокам (по индексам), что минимизирует пересылки, обеспечивает линейный доступ к памяти, упрощает векторизацию. Операции в основном локальны: суммирование внутри сегмента. Глобальная часть — это только обработка сумм сегментов/процессов (малый объём).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Оценка сложности:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для массива длины &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;, при &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; параллельных единицах (нити/процессы):&lt;br /&gt;
* &#039;&#039;&#039;Локальные операции:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; \frac{N}{P} &amp;lt;/math&amp;gt; сложений на каждую нить/процесс&lt;br /&gt;
* &#039;&#039;&#039;Глобальные операции по суммам блоков:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; сложений в сумме, либо &amp;lt;math&amp;gt; \log P &amp;lt;/math&amp;gt; шагов в дереве&lt;br /&gt;
* &#039;&#039;&#039;Объем пересылок (MPI)&#039;&#039;&#039;: один-два числа на процесс, не зависящий от &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, вычислительная сложность остаётся &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt;, а масштабируемость в основном ограничивается коммуникацией по &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; и пропускной способностью памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Использование конкретных технологий:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Параллельная реализация алгоритма частичных сумм строится как двух–трёхступенчатое сканирование: локальное (внутри блока/процесса), глобальное по блокам/процессам и последующая корректировка, что одинаково хорошо ложится на модели OpenMP, MPI, CUDA и схемы векторизации.&lt;br /&gt;
&lt;br /&gt;
===  Результаты прогонов ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===  Выводы для классов архитектур ===&lt;br /&gt;
&lt;br /&gt;
В целом, для алгоритма частичных сумм на всех архитектурах ключевой фактор — организация памяти (линейный доступ, блочная/локальная работа, минимизация пересылок). Конкретные технологии (OpenMP, MPI, CUDA, директивы SIMD) в основном «оборачивают» одну и ту же двух–трёхэтапную схему: локальное сканирование, префикс по агрегированным суммам и корректировка результатов.&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30211</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30211"/>
		<updated>2025-12-07T23:09:59Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления всех частных сумм массива порядка &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; с помощью алгоритма в его параллельном варианте требуется выполнить  &amp;lt;math&amp;gt; (\log_{2} n)&amp;lt;/math&amp;gt; ярусов с убывающим параллелизмом: от &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; операции суммирования на ярус. &lt;br /&gt;
В предположении доступности неограниченного числа необходимых процессоров  требуется &amp;lt;math&amp;gt; O(n \log n)&amp;lt;/math&amp;gt; операций при &amp;lt;math&amp;gt; p = n &amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt; времени. При классификации по  высоте ЯПФ алгоритм имеет логарифмическую высоту &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt;,а при классификации по ширине ЯПФ алгоритм имеет линейную ширину ярусов &amp;lt;math&amp;gt; O(n)&amp;lt;/math&amp;gt;, реализуя массовый координатный параллелизм по индексу процессорных элементов.&lt;br /&gt;
Максимальное ускорение ограничено &amp;lt;math&amp;gt; O(\frac{n}{\log n})&amp;lt;/math&amp;gt; из закона Амдала. &lt;br /&gt;
Наиболее эффективен при &amp;lt;math&amp;gt;n ≫ p ≥ \log n&amp;lt;/math&amp;gt;. Поскольку эффективность алгоритма уменьшается при росте &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; и составляет &amp;lt;math&amp;gt; O(\frac{1}{\log n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: Массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Формула: &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые особенности&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Вход и выход одинакового размера и типа&lt;br /&gt;
# Минимум &amp;lt;math&amp;gt; 2n &amp;lt;/math&amp;gt; элементов памяти (вход + выход)&lt;br /&gt;
# Можно перезаписать входной массив с целью экономии памяти&lt;br /&gt;
# Последний элемент &amp;lt;math&amp;gt; s_n &amp;lt;/math&amp;gt; содержит сумму всех входных чисел&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Переполнение: Риск для целых чисел при больших &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Точность: Накопление ошибок для чисел с плавающей точкой&lt;br /&gt;
* Память: Максимальный &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ограничен доступной памятью&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в предположении доступности неограниченного числа необходимых процессоров, является &amp;lt;math&amp;gt; \frac{n}{\log_{2} n}&amp;lt;/math&amp;gt; отношение линейной к логарифмической, ограничено законом Амдала. &lt;br /&gt;
Алгоритм дает существенное теоретическое ускорение, почти линейное с эффективностью &amp;lt;math&amp;gt; \frac{1}{\log_{2} n}&amp;lt;/math&amp;gt;.&lt;br /&gt;
При этом вычислительная мощность алгоритма, как отношение числа арифметических операций к суммарному объему входных и выходных данных растет как &amp;lt;math&amp;gt; \log n&amp;lt;/math&amp;gt;: при больших &amp;lt;math&amp;gt; n&amp;lt;/math&amp;gt; на один элемент данных приходится все больше операций. Это положительный момент для реализации на ускорителях и сопроцессорах: накладные расходы на пересылку данных относительно стоимости вычислений снижаются.&lt;br /&gt;
Для целых чисел алгоритм абсолютно устойчив, получаем точный результат при отсутствии переполнения. Для чисел с плавающей точкой условно устойчив, поскольку накапливается ошибка округления, где погрешность &amp;lt;math&amp;gt; O(n · ε)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; ε &amp;lt;/math&amp;gt; - машинная точность.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм сбалансирован, поскольку лишь одна операция сложения, нет умножений/делений и.т.д. Алгоритм полностью детерминирован, поскольку число этапов фиксировано и равно &amp;lt;math&amp;gt; \log_{2} n&amp;lt;/math&amp;gt;, набор операций, выполняемых каждым ПЭ на каждом этапе заранее известен и не зависит от входных данных, отсутствуют ветвления по данным, циклы с выходом по точности, использование случайных чисел и.т.п.&amp;lt;br&amp;gt;&lt;br /&gt;
В алгоритме нет «массовых рассылок» скалярных величин с большой степенью исхода одной вершины. Это снижает требования к механизмам широковещательной передачи и упрощает эффективный доступ к данным: каждый результат либо остаётся локальным, либо передаётся ограниченному числу соседей по коммуникационной схеме.&amp;lt;br&amp;gt;&lt;br /&gt;
В линейной системе координат присутствуют длинные дуги, что требует аккуратного отображения на реальную топологию, но при подходящем выборе топологии эти дуги становятся локальными.&amp;lt;br&amp;gt;&lt;br /&gt;
Граф алгоритма регулярно устроен и допускает компактные укладки и конвейеризацию при реализации на специализированных архитектурах.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
===  Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Стандартная последовательная реализация использует простую рекуррентную формулу: каждая следующая частичная сумма вычисляется как сумма предыдущей частичной суммы и текущего элемента массива. Это естественное решение с линейной сложностью &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt;, где выполняется ровно &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; операций сложения. Реализация сталкивается с фундаментальным выбором: сохранять исходные данные, создавая отдельный массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, тем самым увеличивая использование памяти в 2 раза, либо перезаписывать исходный массив, что позволяет экономить память, однако безвозвратно уничтожает входные данные. Такой выбор критичен при работе с большими массивами, где объем памяти становится ограничивающим фактором. &amp;lt;br&amp;gt;&lt;br /&gt;
Для массивов, превышающих размер кэш-памяти процессора, применяется блочная стратегия. Массив разбивается на блоки размером M, где M выбирается таким образом, чтобы блок полностью помещался в кэш L1 или L2. Типичные значения M составляют 16-64 тысяч элементов для 32-битных чисел. Внутри каждого блока последовательно считаются частичные суммы, для блоков хранятся их полные суммы. При переходе к следующему блоку к его элементам добавляется накопленная сумма всех предыдущих блоков. Это улучшает работу с кэш-памятью и даёт удобную основу для параллельных версий. &amp;lt;br&amp;gt;&lt;br /&gt;
Говоря про разрядность, часто нет необходимости выполнять все операции в double. На практике разумен вариант: элементы хранятся в float, а накопитель суммы — в double. Это уменьшает ошибки округления при небольших накладных расходах. Для целых данных следует выбирать достаточно широкий тип (обычно 64-битный), чтобы избежать переполнения.&amp;lt;br&amp;gt;&lt;br /&gt;
Ресурс параллелизма непосредственно в линейном цикле ограничен (каждая итерация зависит от предыдущей), но за счёт ассоциативности сложения алгоритм можно эквивалентно преобразовать в блочную или другие формы. Такие формы удобны для распараллеливания и реализации на многоядерных системах и кластерах. Векторизация ограничена зависимостью между итерациями, но эффективность улучшается за счёт выравнивания данных, линейного доступа и использования более узких типов (float).&lt;br /&gt;
С точки зрения различных платформ:&lt;br /&gt;
* на &#039;&#039;&#039;многоядерных SMP-узлах&#039;&#039;&#039; блоки естественно распределяются по потокам&lt;br /&gt;
* на &#039;&#039;&#039;векторных и GPU-архитектурах&#039;&#039;&#039; используются деревообразные формы&lt;br /&gt;
* на &#039;&#039;&#039;кластерах&#039;&#039;&#039; частичные суммы считаются локально с последующей глобальной коррекцией&lt;br /&gt;
&lt;br /&gt;
===  Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ввиду слабой распространённости задачи нахождения частных сумм в библиотеках данный алгоритм обычно не содержится. &amp;lt;br&amp;gt;&lt;br /&gt;
Для алгоритма вычисления всех частичных сумм по одномерному массиву естественно использовать иерархический ресурс параллелизма.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Иерархия параллелизма:&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;Векторный уровень (SIMD)&#039;&#039;&#039;&lt;br /&gt;
Внутри одного потока данные обрабатываются блоками, для которых сначала вычисляются локальные суммы, затем выполняется локальный префикс внутри блока. Это даёт массовый параллелизм на уровне регистров.&lt;br /&gt;
* &#039;&#039;&#039;Уровень нитей / потоков (OpenMP)&#039;&#039;&#039;&lt;br /&gt;
Массив делится на &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; непрерывных сегментов. Каждый поток считает локальные частичные суммы внутри своего сегмента, затем формируется массив из сумм сегментов длины &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt;. По этому массиву выполняется префиксная сумма (последовательно или параллельно). Полученные &amp;quot;смещения&amp;quot; добавляются ко всем элементам соответствующих сегментов. &amp;lt;br&amp;gt;&lt;br /&gt;
Количество операций: примерно &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt; арифметики + &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; для обработки сумм сегментов на потоках. &amp;lt;br&amp;gt;&lt;br /&gt;
Объем дополнительных данных - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
* &#039;&#039;&#039;Уровень процессов (MPI, кластеры)&#039;&#039;&#039;&lt;br /&gt;
Аналогично нитям ,каждый MPI-процесс хранит свой участок массива (распределение по непрерывным блокам), локально считает частичные суммы. Далее выполняется коллективная операция MPI_Scan или эквивалентная схема с MPI_Allgather/MPI_Bcast для префиксной суммы по суммам процессов. Процессы добавляют своё смещение ко всем локальным элементам.&lt;br /&gt;
Объем коммуникаций: по суммам процессов - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; чисел (обычно одно-два double/int64 на процесс), число шагов ~ &amp;lt;math&amp;gt; O(\log P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Распределение операций и данных:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данные удобно распределять по непрерывным блокам (по индексам), что минимизирует пересылки, обеспечивает линейный доступ к памяти, упрощает векторизацию. Операции в основном локальны: суммирование внутри сегмента. Глобальная часть — это только обработка сумм сегментов/процессов (малый объём).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Оценка сложности:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для массива длины &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;, при &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; параллельных единицах (нити/процессы):&lt;br /&gt;
* &#039;&#039;&#039;Локальные операции:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; \frac{N}{P} &amp;lt;/math&amp;gt; сложений на каждую нить/процесс&lt;br /&gt;
* &#039;&#039;&#039;Глобальные операции по суммам блоков:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; сложений в сумме, либо &amp;lt;math&amp;gt; \log P &amp;lt;/math&amp;gt; шагов в дереве&lt;br /&gt;
* &#039;&#039;&#039;Объем пересылок (MPI)&#039;&#039;&#039;: один-два числа на процесс, не зависящий от &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, вычислительная сложность остаётся &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt;, а масштабируемость в основном ограничивается коммуникацией по &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; и пропускной способностью памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Использование конкретных технологий:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Параллельная реализация алгоритма частичных сумм строится как двух–трёхступенчатое сканирование: локальное (внутри блока/процесса), глобальное по блокам/процессам и последующая корректировка, что одинаково хорошо ложится на модели OpenMP, MPI, CUDA и схемы векторизации.&lt;br /&gt;
&lt;br /&gt;
===  Результаты прогонов ===&lt;br /&gt;
===  Выводы для классов архитектур ===&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30210</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30210"/>
		<updated>2025-12-07T23:06:12Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления всех частных сумм массива порядка &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; с помощью алгоритма в его параллельном варианте требуется выполнить  &amp;lt;math&amp;gt; (\log_{2} n)&amp;lt;/math&amp;gt; ярусов с убывающим параллелизмом: от &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; операции суммирования на ярус. &lt;br /&gt;
В предположении доступности неограниченного числа необходимых процессоров  требуется &amp;lt;math&amp;gt; O(n \log n)&amp;lt;/math&amp;gt; операций при &amp;lt;math&amp;gt; p = n &amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt; времени. При классификации по  высоте ЯПФ алгоритм имеет логарифмическую высоту &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt;,а при классификации по ширине ЯПФ алгоритм имеет линейную ширину ярусов &amp;lt;math&amp;gt; O(n)&amp;lt;/math&amp;gt;, реализуя массовый координатный параллелизм по индексу процессорных элементов.&lt;br /&gt;
Максимальное ускорение ограничено &amp;lt;math&amp;gt; O(\frac{n}{\log n})&amp;lt;/math&amp;gt; из закона Амдала. &lt;br /&gt;
Наиболее эффективен при &amp;lt;math&amp;gt;n ≫ p ≥ \log n&amp;lt;/math&amp;gt;. Поскольку эффективность алгоритма уменьшается при росте &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; и составляет &amp;lt;math&amp;gt; O(\frac{1}{\log n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: Массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Формула: &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые особенности&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Вход и выход одинакового размера и типа&lt;br /&gt;
# Минимум &amp;lt;math&amp;gt; 2n &amp;lt;/math&amp;gt; элементов памяти (вход + выход)&lt;br /&gt;
# Можно перезаписать входной массив с целью экономии памяти&lt;br /&gt;
# Последний элемент &amp;lt;math&amp;gt; s_n &amp;lt;/math&amp;gt; содержит сумму всех входных чисел&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Переполнение: Риск для целых чисел при больших &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Точность: Накопление ошибок для чисел с плавающей точкой&lt;br /&gt;
* Память: Максимальный &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ограничен доступной памятью&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в предположении доступности неограниченного числа необходимых процессоров, является &amp;lt;math&amp;gt; \frac{n}{\log_{2} n}&amp;lt;/math&amp;gt; отношение линейной к логарифмической, ограничено законом Амдала. &lt;br /&gt;
Алгоритм дает существенное теоретическое ускорение, почти линейное с эффективностью &amp;lt;math&amp;gt; \frac{1}{\log_{2} n}&amp;lt;/math&amp;gt;.&lt;br /&gt;
При этом вычислительная мощность алгоритма, как отношение числа арифметических операций к суммарному объему входных и выходных данных растет как &amp;lt;math&amp;gt; \log n&amp;lt;/math&amp;gt;: при больших &amp;lt;math&amp;gt; n&amp;lt;/math&amp;gt; на один элемент данных приходится все больше операций. Это положительный момент для реализации на ускорителях и сопроцессорах: накладные расходы на пересылку данных относительно стоимости вычислений снижаются.&lt;br /&gt;
Для целых чисел алгоритм абсолютно устойчив, получаем точный результат при отсутствии переполнения. Для чисел с плавающей точкой условно устойчив, поскольку накапливается ошибка округления, где погрешность &amp;lt;math&amp;gt; O(n · ε)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; ε &amp;lt;/math&amp;gt; - машинная точность.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм сбалансирован, поскольку лишь одна операция сложения, нет умножений/делений и.т.д. Алгоритм полностью детерминирован, поскольку число этапов фиксировано и равно &amp;lt;math&amp;gt; \log_{2} n&amp;lt;/math&amp;gt;, набор операций, выполняемых каждым ПЭ на каждом этапе заранее известен и не зависит от входных данных, отсутствуют ветвления по данным, циклы с выходом по точности, использование случайных чисел и.т.п.&amp;lt;br&amp;gt;&lt;br /&gt;
В алгоритме нет «массовых рассылок» скалярных величин с большой степенью исхода одной вершины. Это снижает требования к механизмам широковещательной передачи и упрощает эффективный доступ к данным: каждый результат либо остаётся локальным, либо передаётся ограниченному числу соседей по коммуникационной схеме.&amp;lt;br&amp;gt;&lt;br /&gt;
В линейной системе координат присутствуют длинные дуги, что требует аккуратного отображения на реальную топологию, но при подходящем выборе топологии эти дуги становятся локальными.&amp;lt;br&amp;gt;&lt;br /&gt;
Граф алгоритма регулярно устроен и допускает компактные укладки и конвейеризацию при реализации на специализированных архитектурах.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
===  Особенности реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Стандартная последовательная реализация использует простую рекуррентную формулу: каждая следующая частичная сумма вычисляется как сумма предыдущей частичной суммы и текущего элемента массива. Это естественное решение с линейной сложностью &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt;, где выполняется ровно &amp;lt;math&amp;gt; n - 1&amp;lt;/math&amp;gt; операций сложения. Реализация сталкивается с фундаментальным выбором: сохранять исходные данные, создавая отдельный массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; размера &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, тем самым увеличивая использование памяти в 2 раза, либо перезаписывать исходный массив, что позволяет экономить память, однако безвозвратно уничтожает входные данные. Такой выбор критичен при работе с большими массивами, где объем памяти становится ограничивающим фактором. &amp;lt;br&amp;gt;&lt;br /&gt;
Для массивов, превышающих размер кэш-памяти процессора, применяется блочная стратегия. Массив разбивается на блоки размером M, где M выбирается таким образом, чтобы блок полностью помещался в кэш L1 или L2. Типичные значения M составляют 16-64 тысяч элементов для 32-битных чисел. Внутри каждого блока последовательно считаются частичные суммы, для блоков хранятся их полные суммы. При переходе к следующему блоку к его элементам добавляется накопленная сумма всех предыдущих блоков. Это улучшает работу с кэш-памятью и даёт удобную основу для параллельных версий. &amp;lt;br&amp;gt;&lt;br /&gt;
Говоря про разрядность, часто нет необходимости выполнять все операции в double. На практике разумен вариант: элементы хранятся в float, а накопитель суммы — в double. Это уменьшает ошибки округления при небольших накладных расходах. Для целых данных следует выбирать достаточно широкий тип (обычно 64-битный), чтобы избежать переполнения.&amp;lt;br&amp;gt;&lt;br /&gt;
Ресурс параллелизма непосредственно в линейном цикле ограничен (каждая итерация зависит от предыдущей), но за счёт ассоциативности сложения алгоритм можно эквивалентно преобразовать в блочную или другие формы. Такие формы удобны для распараллеливания и реализации на многоядерных системах и кластерах. Векторизация ограничена зависимостью между итерациями, но эффективность улучшается за счёт выравнивания данных, линейного доступа и использования более узких типов (float).&lt;br /&gt;
С точки зрения различных платформ:&lt;br /&gt;
* на &#039;&#039;&#039;многоядерных SMP-узлах&#039;&#039;&#039; блоки естественно распределяются по потокам&lt;br /&gt;
* на &#039;&#039;&#039;векторных и GPU-архитектурах&#039;&#039;&#039; используются деревообразные формы&lt;br /&gt;
* на &#039;&#039;&#039;кластерах&#039;&#039;&#039; частичные суммы считаются локально с последующей глобальной коррекцией&lt;br /&gt;
&lt;br /&gt;
===  Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Ввиду слабой распространённости задачи нахождения частных сумм в библиотеках данный алгоритм обычно не содержится. &amp;lt;br&amp;gt;&lt;br /&gt;
Для алгоритма вычисления всех частичных сумм по одномерному массиву естественно использовать иерархический ресурс параллелизма.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Иерархия параллелизма:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Векторный уровень (SIMD)&#039;&#039;&#039;&lt;br /&gt;
Внутри одного потока данные обрабатываются блоками, для которых сначала вычисляются локальные суммы, затем выполняется локальный префикс внутри блока. Это даёт массовый параллелизм на уровне регистров.&lt;br /&gt;
# &#039;&#039;&#039;Уровень нитей / потоков (OpenMP)&#039;&#039;&#039;&lt;br /&gt;
Массив делится на &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; непрерывных сегментов. Каждый поток считает локальные частичные суммы внутри своего сегмента, затем формируется массив из сумм сегментов длины &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt;. По этому массиву выполняется префиксная сумма (последовательно или параллельно). Полученные &amp;quot;смещения&amp;quot; добавляются ко всем элементам соответствующих сегментов. &amp;lt;br&amp;gt;&lt;br /&gt;
Количество операций: примерно &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt; арифметики + &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; для обработки сумм сегментов на потоках. &amp;lt;br&amp;gt;&lt;br /&gt;
Объем дополнительных данных - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;Уровень процессов (MPI, кластеры)&#039;&#039;&#039;&lt;br /&gt;
Аналогично нитям ,каждый MPI-процесс хранит свой участок массива (распределение по непрерывным блокам), локально считает частичные суммы. Далее выполняется коллективная операция MPI_Scan или эквивалентная схема с MPI_Allgather/MPI_Bcast для префиксной суммы по суммам процессов. Процессы добавляют своё смещение ко всем локальным элементам.&lt;br /&gt;
Объем коммуникаций: по суммам процессов - &amp;lt;math&amp;gt; O(P) &amp;lt;/math&amp;gt; чисел (обычно одно-два double/int64 на процесс), число шагов ~ &amp;lt;math&amp;gt; O(\log P) &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Распределение операций и данных:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Данные удобно распределять по непрерывным блокам (по индексам), что минимизирует пересылки, обеспечивает линейный доступ к памяти, упрощает векторизацию. Операции в основном локальны: суммирование внутри сегмента. Глобальная часть — это только обработка сумм сегментов/процессов (малый объём).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Оценка сложности:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для массива длины &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;, при &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; параллельных единицах (нити/процессы):&lt;br /&gt;
* &#039;&#039;&#039;Локальные операции:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; \frac{N}{P} &amp;lt;/math&amp;gt; сложений на каждую нить/процесс&lt;br /&gt;
* &#039;&#039;&#039;Глобальные операции по суммам блоков:&#039;&#039;&#039; ≈ &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; сложений в сумме, либо &amp;lt;math&amp;gt; \log P &amp;lt;/math&amp;gt; шагов в дереве&lt;br /&gt;
* &#039;&#039;&#039;Объем пересылок (MPI)&#039;&#039;&#039;: один-два числа на процесс, не зависящий от &amp;lt;math&amp;gt; N &amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, вычислительная сложность остаётся &amp;lt;math&amp;gt; O(N) &amp;lt;/math&amp;gt;, а масштабируемость в основном ограничивается коммуникацией по &amp;lt;math&amp;gt; P &amp;lt;/math&amp;gt; и пропускной способностью памяти.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Использование конкретных технологий:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
Параллельная реализация алгоритма частичных сумм строится как двух–трёхступенчатое сканирование: локальное (внутри блока/процесса), глобальное по блокам/процессам и последующая корректировка, что одинаково хорошо ложится на модели OpenMP, MPI, CUDA и схемы векторизации.&lt;br /&gt;
&lt;br /&gt;
===  Результаты прогонов ===&lt;br /&gt;
===  Выводы для классов архитектур ===&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30205</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30205"/>
		<updated>2025-12-07T21:22:37Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления всех частных сумм массива порядка &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; с помощью алгоритма в его параллельном варианте требуется выполнить  &amp;lt;math&amp;gt; (\log_{2} n)&amp;lt;/math&amp;gt; ярусов с убывающим параллелизмом: от &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; операции суммирования на ярус. &lt;br /&gt;
В предположении доступности неограниченного числа необходимых процессоров  требуется &amp;lt;math&amp;gt; O(n \log n)&amp;lt;/math&amp;gt; операций при &amp;lt;math&amp;gt; p = n &amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt; времени. При классификации по  высоте ЯПФ алгоритм имеет логарифмическую высоту &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt;,а при классификации по ширине ЯПФ алгоритм имеет линейную ширину ярусов &amp;lt;math&amp;gt; O(n)&amp;lt;/math&amp;gt;, реализуя массовый координатный параллелизм по индексу процессорных элементов.&lt;br /&gt;
Максимальное ускорение ограничено &amp;lt;math&amp;gt; O(\frac{n}{\log n})&amp;lt;/math&amp;gt; из закона Амдала. &lt;br /&gt;
Наиболее эффективен при &amp;lt;math&amp;gt;n ≫ p ≥ \log n&amp;lt;/math&amp;gt;. Поскольку эффективность алгоритма уменьшается при росте &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; и составляет &amp;lt;math&amp;gt; O(\frac{1}{\log n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: Массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Формула: &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые особенности&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Вход и выход одинакового размера и типа&lt;br /&gt;
# Минимум &amp;lt;math&amp;gt; 2n &amp;lt;/math&amp;gt; элементов памяти (вход + выход)&lt;br /&gt;
# Можно перезаписать входной массив с целью экономии памяти&lt;br /&gt;
# Последний элемент &amp;lt;math&amp;gt; s_n &amp;lt;/math&amp;gt; содержит сумму всех входных чисел&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Переполнение: Риск для целых чисел при больших &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Точность: Накопление ошибок для чисел с плавающей точкой&lt;br /&gt;
* Память: Максимальный &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ограничен доступной памятью&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Соотношение последовательной и параллельной сложности в предположении доступности неограниченного числа необходимых процессоров, является &amp;lt;math&amp;gt; \frac{n}{\log_{2} n}&amp;lt;/math&amp;gt; отношение линейной к логарифмической, ограничено законом Амдала. &lt;br /&gt;
Алгоритм дает существенное теоретическое ускорение, почти линейное с эффективностью &amp;lt;math&amp;gt; \frac{1}{\log_{2} n}&amp;lt;/math&amp;gt;.&lt;br /&gt;
При этом вычислительная мощность алгоритма, как отношение числа арифметических операций к суммарному объему входных и выходных данных растет как &amp;lt;math&amp;gt; \log n&amp;lt;/math&amp;gt;: при больших &amp;lt;math&amp;gt; n&amp;lt;/math&amp;gt; на один элемент данных приходится все больше операций. Это положительный момент для реализации на ускорителях и сопроцессорах: накладные расходы на пересылку данных относительно стоимости вычислений снижаются.&lt;br /&gt;
Для целых чисел алгоритм абсолютно устойчив, получаем точный результат при отсутствии переполнения. Для чисел с плавающей точкой условно устойчив, поскольку накапливается ошибка округления, где погрешность &amp;lt;math&amp;gt; O(n · ε)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt; ε &amp;lt;/math&amp;gt; - машинная точность.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм сбалансирован, поскольку лишь одна операция сложения, нет умножений/делений и.т.д. Алгоритм полностью детерминирован, поскольку число этапов фиксировано и равно &amp;lt;math&amp;gt; \log_{2} n&amp;lt;/math&amp;gt;, набор операций, выполняемых каждым ПЭ на каждом этапе заранее известен и не зависит от входных данных, отсутствуют ветвления по данным, циклы с выходом по точности, использование случайных чисел и.т.п.&amp;lt;br&amp;gt;&lt;br /&gt;
В алгоритме нет «массовых рассылок» скалярных величин с большой степенью исхода одной вершины. Это снижает требования к механизмам широковещательной передачи и упрощает эффективный доступ к данным: каждый результат либо остаётся локальным, либо передаётся ограниченному числу соседей по коммуникационной схеме.&amp;lt;br&amp;gt;&lt;br /&gt;
В линейной системе координат присутствуют длинные дуги, что требует аккуратного отображения на реальную топологию, но при подходящем выборе топологии эти дуги становятся локальными.&amp;lt;br&amp;gt;&lt;br /&gt;
Граф алгоритма регулярно устроен и допускает компактные укладки и конвейеризацию при реализации на специализированных архитектурах.&lt;br /&gt;
&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
===  Особенности реализации последовательного алгоритма ===&lt;br /&gt;
===  Возможные способы и особенности параллельной реализации алгоритма ===&lt;br /&gt;
===  Результаты прогонов ===&lt;br /&gt;
===  Выводы для классов архитектур ===&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30195</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30195"/>
		<updated>2025-12-07T19:16:21Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления всех частных сумм массива порядка &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; с помощью алгоритма в его параллельном варианте требуется выполнить  &amp;lt;math&amp;gt; (\log_{2} n)&amp;lt;/math&amp;gt; ярусов с убывающим параллелизмом: от &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; операции суммирования на ярус. &lt;br /&gt;
В предположении доступности неограниченного числа необходимых процессоров  требуется &amp;lt;math&amp;gt; O(n \log n)&amp;lt;/math&amp;gt; операций при &amp;lt;math&amp;gt; p = n &amp;lt;/math&amp;gt; за &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt; времени. При классификации по  высоте ЯПФ алгоритм имеет логарифмическую высоту &amp;lt;math&amp;gt; O(\log n)&amp;lt;/math&amp;gt;,а при классификации по ширине ЯПФ алгоритм имеет линейную ширину ярусов &amp;lt;math&amp;gt; O(n)&amp;lt;/math&amp;gt;, реализуя массовый координатный параллелизм по индексу процессорных элементов.&lt;br /&gt;
Максимальное ускорение ограничено &amp;lt;math&amp;gt; O(\frac{n}{\log n})&amp;lt;/math&amp;gt; из закона Амдала. &lt;br /&gt;
Наиболее эффективен при &amp;lt;math&amp;gt;n ≫ p ≥ \log n&amp;lt;/math&amp;gt;. Поскольку эффективность алгоритма уменьшается при росте &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; и составляет &amp;lt;math&amp;gt; O(\frac{1}{\log n})&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: Массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Формула: &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые особенности&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Вход и выход одинакового размера и типа&lt;br /&gt;
# Минимум &amp;lt;math&amp;gt; 2n &amp;lt;/math&amp;gt; элементов памяти (вход + выход)&lt;br /&gt;
# Можно перезаписать входной массив с целью экономии памяти&lt;br /&gt;
# Последний элемент &amp;lt;math&amp;gt; s_n &amp;lt;/math&amp;gt; содержит сумму всех входных чисел&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Переполнение: Риск для целых чисел при больших &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Точность: Накопление ошибок для чисел с плавающей точкой&lt;br /&gt;
* Память: Максимальный &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ограничен доступной памятью&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30194</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30194"/>
		<updated>2025-12-07T18:43:17Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для вычисления всех частных сумм массива порядка &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; с помощью алгоритма в его параллельном варианте требуется выполнить  &amp;lt;math&amp;gt; (log_{2} n)&amp;lt;/math&amp;gt; ярусов с убывающим параллелизмом: от &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; 1 &amp;lt;/math&amp;gt; операции суммирования на ярус.  &lt;br /&gt;
Максимальное ускорение ограничено &amp;lt;math&amp;gt; O(\frac{n}{\log n})&amp;lt;/math&amp;gt;. Наиболее эффективен при &amp;lt;math&amp;gt;n ≫ p ≥ \log n&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Объект: Массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Формула: &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n × sizeof &amp;lt;/math&amp;gt;(тип)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые особенности&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Вход и выход одинакового размера и типа&lt;br /&gt;
# Минимум &amp;lt;math&amp;gt; 2n &amp;lt;/math&amp;gt; элементов памяти (вход + выход)&lt;br /&gt;
# Можно перезаписать входной массив с целью экономии памяти&lt;br /&gt;
# Последний элемент &amp;lt;math&amp;gt; s_n &amp;lt;/math&amp;gt; содержит сумму всех входных чисел&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ограничения&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Переполнение: Риск для целых чисел при больших &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Точность: Накопление ошибок для чисел с плавающей точкой&lt;br /&gt;
* Память: Максимальный &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; ограничен доступной памятью&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30193</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30193"/>
		<updated>2025-12-07T17:11:03Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Обьект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math&amp;gt;)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n x sizeof(тип) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30192</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30192"/>
		<updated>2025-12-07T17:05:05Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Входные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Обьект: одномерный массив чисел &amp;lt;math&amp;gt; X = [x_1,x_2,...,x_n] &amp;lt;/math&lt;br /&gt;
* Тип: Любой числовой (целые, вещественные, комплексные)&lt;br /&gt;
* Размер: &amp;lt;math&amp;gt; n &amp;lt;/math элементов (&amp;lt;math&amp;gt; n ≥ 0 &amp;lt;/math)&lt;br /&gt;
* Объем памяти: &amp;lt;math&amp;gt; n x sizeof(тип) &amp;lt;/math&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выходные данные&#039;&#039;&#039; &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;math&amp;gt; n &amp;lt;/math&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30187</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30187"/>
		<updated>2025-12-07T00:54:36Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
&lt;br /&gt;
* Входные данные: массив &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; (элементы &amp;lt;math&amp;gt;x_i&amp;lt;/math&amp;gt;)&lt;br /&gt;
* Дополнительные ограничения: отсутствуют&lt;br /&gt;
* Объём входных данных: &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Выходные данные: сумма элементов массива&lt;br /&gt;
* Объём выходных данных:&lt;br /&gt;
&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30186</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30186"/>
		<updated>2025-12-07T00:48:46Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
На рис.2 изображён граф алгоритма. В данном случае выполнено суммирование 8 элементов массива.&amp;lt;br&amp;gt;&lt;br /&gt;
* Видно, что параллельный алгоритм вычисления всех частных сумм требует &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; сложений со степенью параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;, если для обеспечения однородности вычислительной схемы на ПЭ (процессорном элементе), для которых нет данных слева, отправлять нулевые значения.&lt;br /&gt;
* Каждая операция алгоритма имеет максимально возможную степень параллелизма &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt;&lt;br /&gt;
* Общее число скалярных арифметических операций увеличилось с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt;, а время выполнения задачи уменьшилось&lt;br /&gt;
Таким образом, увеличение степени параллелизма на каждом этапе от 1 до n происходит за счет существенного увеличения числа скалярных арифметических операций.&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30185</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30185"/>
		<updated>2025-12-07T00:40:47Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной вычислительный фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30184</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30184"/>
		<updated>2025-12-07T00:40:28Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: /* Схема реализации последовательного алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Фрагмент кода на С++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне.&lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30183</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30183"/>
		<updated>2025-12-07T00:39:39Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Фрагмент кода на С++:&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне. &lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
&lt;br /&gt;
[[File:Model.png|center|1000px|thumb|Рис. 2 Диаграмма маршрутизации параллельного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30182</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30182"/>
		<updated>2025-12-07T00:29:49Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Фрагмент кода на С++:&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]] как центрировать описание&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне. &lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм &#039;&#039;&#039;линейна&#039;&#039;&#039; по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения, где &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; - размер массива и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30181</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30181"/>
		<updated>2025-12-07T00:27:28Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Фрагмент кода на С++:&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|1000px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]] как центрировать описание&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем изображено на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне. &lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Последовательная сложность алгоритма вычисления всех частичных сумм линейна по размеру входных данных: требуется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; операции сложения и &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; обращений к памяти.&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30180</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30180"/>
		<updated>2025-12-07T00:11:46Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Фрагмент кода на С++:&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n \cdot \log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(\log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последовательный&lt;br /&gt;
[[File:Model2.png|center|500px|thumb|Рис. 1 Диаграмма маршрутизации последовательного алгоритма вычисления всех частных сумм]]&lt;br /&gt;
* Соотношение между способом хранения данных, арифметическими операциями и временем можно изобразить на диаграмме маршрутизации&lt;br /&gt;
* Последовательность вычислений перемещается снизу вверх.&lt;br /&gt;
*  Операции, которые могут выполняться параллельно, показаны на одном и том же вертикальном уровне. &lt;br /&gt;
&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Model2.png&amp;diff=30179</id>
		<title>Файл:Model2.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Model2.png&amp;diff=30179"/>
		<updated>2025-12-07T00:07:58Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;h&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30178</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30178"/>
		<updated>2025-12-06T23:59:09Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Фрагмент кода на С++:&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
* Последовательный алгоритм выполняет &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(n) &amp;lt;/math&amp;gt; времени на 1 процессоре&lt;br /&gt;
* Параллельный алгоритм выполняет &amp;lt;math&amp;gt; O(n · log n) &amp;lt;/math&amp;gt; операций за &amp;lt;math&amp;gt; O(log n) &amp;lt;/math&amp;gt; времени на &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; процессорах&lt;br /&gt;
* При &amp;lt;math&amp;gt; n = 1 &amp;lt;/math&amp;gt; или при выполнении на одном ядре параллельный алгоритм вырождается в последоватьльный&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30177</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30177"/>
		<updated>2025-12-06T23:09:46Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Фрагмент кода на С++:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    // Вычисление частичных сумм&lt;br /&gt;
    s[0] = a[0];&lt;br /&gt;
    for (int i = 1; i &amp;lt; n; i++) &lt;br /&gt;
    {&lt;br /&gt;
        s[i] = s[i - 1] + a[i];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30176</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30176"/>
		<updated>2025-12-06T23:08:44Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу &#039;&#039;алгоритмов сдваивания&#039;&#039;. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
#* Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
#* Для каждого индекса &amp;lt;math&amp;gt; i ≤ d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Начало:&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 1 (d=1):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Шаг 2 (d=2):&#039;&#039;&#039; &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Вычислительное ядро параллельного алгоритма вычисления всех частных сумм представляет собой операцию: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; s_i = s_i + s_{i-d} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где:&lt;br /&gt;
* &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; - текущее значение в процессоре &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt;&lt;br /&gt;
* &amp;lt;math&amp;gt; s_{i-d} &amp;lt;/math&amp;gt; - значение из процессора, находящегося на расстоянии &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; слева&lt;br /&gt;
* &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt; - расстояние между процессорами, которое удваивается на каждом шаге&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Характеристики вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
# &#039;&#039;&#039;Простота:&#039;&#039;&#039; Каждая операция - одно сложение&lt;br /&gt;
# &#039;&#039;&#039;Регулярность:&#039;&#039;&#039; На каждом шаге выполняется одинаковый тип операций, только меняется расстояние&lt;br /&gt;
# &#039;&#039;&#039;Параллельность:&#039;&#039;&#039; Все операции на одном шаге могут выполняться одновременно разными процессорами&lt;br /&gt;
# &#039;&#039;&#039;Коммуникационная интенсивность:&#039;&#039;&#039; Основная сложность - в организации быстрого обмена данными между процессорами, а не в самих вычислениях&lt;br /&gt;
&lt;br /&gt;
На первом шаге выполняется &amp;lt;math&amp;gt; n - 1 &amp;lt;/math&amp;gt; сложений, на втором &amp;lt;math&amp;gt; n - 2 &amp;lt;/math&amp;gt; сложений и так далее. Несмотря на то, что общее количество операций &amp;lt;math&amp;gt; (n · log_{2} n)&amp;lt;/math&amp;gt; больше чем в последовательном алгоритме &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; операций, время выполнения сокращается с &amp;lt;math&amp;gt; n &amp;lt;/math&amp;gt; шагов до &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; шагов благодаря параллелизму.&lt;br /&gt;
&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Алгоритм вычисления всех частных сумм не использует в качестве составных частей другие сложные алгоритмы, но может быть представлен как последовательность однотипных макрошагов (или итераций). Каждый макрошаг состоит из двух базовых операций: &#039;&#039;коммуникационной&#039;&#039; (передача данных) и &#039;&#039;вычислительной&#039;&#039; (суммирование).&lt;br /&gt;
&lt;br /&gt;
Алгоритм представляет собой последовательность &amp;lt;math&amp;gt; log_{2} n &amp;lt;/math&amp;gt; итераций. &amp;lt;br&amp;gt;&lt;br /&gt;
Каждая итерация для всех активных процессоров представима следующими двумя этапами:&lt;br /&gt;
# Передача данных на расстояние &amp;lt;math&amp;gt; d &amp;lt;/math&amp;gt;&lt;br /&gt;
# Сложение: &amp;lt;math&amp;gt; s[i] = s[i] + &amp;lt;/math&amp;gt; полученное_значение&lt;br /&gt;
&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
&lt;br /&gt;
Для заданного массива чисел &amp;lt;math&amp;gt; X = [x_1, x_2,...,x_n]&amp;lt;/math&amp;gt; требуется вычислить массив частичных сумм &amp;lt;math&amp;gt; S = [s_1,s_2,...,s_n] &amp;lt;/math&amp;gt;, где&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = \sum_{i=1}^n x_i, 1 ≤ k ≤ n &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
В последовательном алгоритме частичные суммы можно вычислить весьма просто из рекуррентного соотношения:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S_k = S_{k-1} + x_k, \quad k = 1,2,\ldots,n; \quad S_0 = 0 &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Фрагмент кода на С++:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
// Вычисление частичных сумм&lt;br /&gt;
s[0] = a[0];&lt;br /&gt;
for (int i = 1; i &amp;lt; n; ++i) &lt;br /&gt;
{&lt;br /&gt;
    s[i] = s[i - 1] + a[i];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30166</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30166"/>
		<updated>2025-12-06T18:59:16Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу алгоритмов сдваивания. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
## Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
## Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
## Для каждого индекса &amp;lt;math&amp;gt; i &amp;lt;=d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
Простой пример для &amp;lt;math&amp;gt; n = 4: &amp;lt;/math&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
* Начало: &amp;lt;math&amp;gt; [x_1,x_2,x_3,x_4] &amp;lt;/math&amp;gt;&lt;br /&gt;
* Шаг 1 (d=1): &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_2 + x_3, x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
* Шаг 2 (d-2): &amp;lt;math&amp;gt; [x_1, x_1 + x_2, x_1 + x_2 + x_3, x_1 + x_2 + x_3 + x_4]&amp;lt;/math&amp;gt;&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30165</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30165"/>
		<updated>2025-12-06T18:54:57Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу алгоритмов сдваивания. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&amp;lt;br&amp;gt;&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм широко используется в параллельных вычислениях.&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
Пусть дан массив чисел: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; &amp;lt;br&amp;gt;&lt;br /&gt;
Необходимо найти массив &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \{s_1,s_2,...,s_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt; где &amp;lt;math&amp;gt; s_i = x_1 + x_2 + ... + x_i&amp;lt;/math&amp;gt; для всех &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; от 1 до n.&lt;br /&gt;
Алгоритм выполняется за &amp;lt;math&amp;gt; k = log_{2} n &amp;lt;/math&amp;gt; шагов: &amp;lt;br&amp;gt;&lt;br /&gt;
# Каждый процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; хранит значение &amp;lt;math&amp;gt; s_i = x_i &amp;lt;/math&amp;gt;&lt;br /&gt;
# Для каждого шага &amp;lt;math&amp;gt; t &amp;lt;/math&amp;gt; от 1 до k:&lt;br /&gt;
## Вычисляем расстояние &amp;lt;math&amp;gt; d = 2^{(t-1)} &amp;lt;/math&amp;gt;&lt;br /&gt;
## Для каждого индекса &amp;lt;math&amp;gt; i &amp;gt; d &amp;lt;/math&amp;gt; процессор &amp;lt;math&amp;gt; i &amp;lt;/math&amp;gt; выполняет: &amp;lt;math&amp;gt; s_i = s_i + s_{i-d}&amp;lt;/math&amp;gt;&lt;br /&gt;
## Для каждого индекса &amp;lt;math&amp;gt; i &amp;lt;=d &amp;lt;/math&amp;gt; значение &amp;lt;math&amp;gt; s_i &amp;lt;/math&amp;gt; остается неизменным&lt;br /&gt;
# После &amp;lt;math&amp;gt;k&amp;lt;/math&amp;gt; шагов массив &amp;lt;math&amp;gt; S &amp;lt;/math&amp;gt; содержит все частные суммы&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30162</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30162"/>
		<updated>2025-12-06T17:30:12Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&amp;lt;br&amp;gt;&lt;br /&gt;
Алгоритм относится к классу алгоритмов сдваивания. Его ключевая идея заключается в том, что на каждом шаге расстояние, на которое передаются и суммируются уже накопленные частичные результаты, удваиваются.&lt;br /&gt;
Входные данные представляют собой массив числовых элементов, для которых определена операция сложения, однако алгоритм может быть обобщен на любую ассоциативную бинарную операцию (умножение, нахождение минимума/максимума, логическое И/ИЛИ и.т.д.).&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30161</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30161"/>
		<updated>2025-12-06T17:20:26Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
Данный алгоритм предназначен для вычисления всех частных сумм заданного массива данных. Для входного массива: &amp;lt;center&amp;gt;&amp;lt;math&amp;gt; X = \{x_1,x_2,...,x_n\} &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
требуется найти массив:&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;math&amp;gt; S = \sum_{i=1}^n x_i &amp;lt;/math&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
такой, что каждый его элемент &amp;lt;math&amp;gt; S[i] &amp;lt;/math&amp;gt; равен сумме всех элементов &amp;lt;math&amp;gt; X &amp;lt;/math&amp;gt; от первого до &amp;lt;math&amp;gt; i&amp;lt;/math&amp;gt;-го включительно.&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30160</id>
		<title>Участник:Bannikov Nikolay/Параллельный алгоритм вычисления всех частных сумм</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9F%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%B2%D1%8B%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F_%D0%B2%D1%81%D0%B5%D1%85_%D1%87%D0%B0%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%81%D1%83%D0%BC%D0%BC&amp;diff=30160"/>
		<updated>2025-12-06T16:07:37Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: Новая страница: «== Свойства и структура алгоритма == === Общее описание алгоритма === ===  Математическое описание алгоритма === ===  Вычислительное ядро алгоритма === ===  Макроструктура алгоритма === ===  Схема реализации последовательного алгоритма === ===  Последовательная сложно...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4%D0%BD%D0%B0%D1%8F_%D1%81%D1%85%D0%B5%D0%BC%D0%B0_%D1%81%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=30037</id>
		<title>Участник:Bannikov Nikolay/Каскадная схема суммирования</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4%D0%BD%D0%B0%D1%8F_%D1%81%D1%85%D0%B5%D0%BC%D0%B0_%D1%81%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=30037"/>
		<updated>2025-11-19T01:35:30Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Каскадная схема суммирования&#039;&#039;&#039; представляет собой алгоритм поэтапного (многоуровневого) сложения нескольких числовых величин, организованных в каскадную структуру. Основная идея заключается в том, что входные данные (слагаемые) группируются и суммируются последовательно на каждом уровне каскада, а полученные промежуточные результаты передаются на следующий уровень для дальнейшего суммирования.&lt;br /&gt;
&lt;br /&gt;
Такая организация позволяет повысить быстродействие за счёт параллельного выполнения частичных сумм и уменьшения задержек при обработке больших массивов данных. Каскадная схема часто используется в цифровых вычислительных устройствах и системах обработки сигналов, где требуется эффективное выполнение операций сложения большого числа аргументов.&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
Пусть имеется набор входных данных: $$X = \{x_1,x_2,...,x_n\} $$&lt;br /&gt;
Необходимо найти их сумму: $$S = \sum_{i=1}^n x_i$$&lt;br /&gt;
В каскадной схеме процесс выполняется в несколько уровней. На каждом уровне производится суммирование попарных элементов предыдущего уровня.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
На первом уровне формируются частичные суммы $$y_{j}^{(1)} = x_{2j-1} + x_{2j}, \quad j = 1,2,...\frac{n}{2}$$&lt;br /&gt;
На втором уровне — суммы результатов первого уровня $$y_{k}^{(2)} = y_{2k-1}^{(1)} + y_{2k}^{(1)}, \quad k = 1,2,...\frac{n}{4}$$&lt;br /&gt;
И так далее, пока не останется одно значение — итоговая сумма $$S = y_1^{(m)}, \quad где \ m = \log_{2} n$$&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
В каскадной схеме суммирования вычислительным ядром является операция попарного сложения элементов &lt;br /&gt;
на каждом уровне каскада. Именно эта часть алгоритма выполняется многократно и определяет основную &lt;br /&gt;
вычислительную нагрузку.&lt;br /&gt;
&lt;br /&gt;
На каждом уровне происходит одинаковая базовая операция: $$y=a+b$$&lt;br /&gt;
где &amp;lt;math&amp;gt;a&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;b&amp;lt;/math&amp;gt; — либо исходные элементы, либо частичные суммы предыдущего уровня.&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Вычислительное ядро включает:&#039;&#039;&#039;&lt;br /&gt;
* Формирование пар чисел&lt;br /&gt;
* Выполнение операции их сложения&lt;br /&gt;
* Передачу полученных частичных сумм на следующий уровень&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Объем вычислительного ядра:&#039;&#039;&#039;&lt;br /&gt;
* Общее количество операций сложения: &amp;lt;math&amp;gt;n-1&amp;lt;/math&amp;gt;&lt;br /&gt;
* Количество уровней каскада: &amp;lt;math&amp;gt;\log_{2} n&amp;lt;/math&amp;gt;&lt;br /&gt;
* Максимальное количество операций на уровне: &amp;lt;math&amp;gt;\frac{n}{2}&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ключевые характеристики ядра:&#039;&#039;&#039;&lt;br /&gt;
* Регулярная структура - все операции однотипны (бинарное сложение)&lt;br /&gt;
* Локальность данных - на каждом уровне вычисления используют только результаты с предыдущего уровня&lt;br /&gt;
* Параллелизм - операции в пределах одного уровня независимы и могут выполняться параллельно&lt;br /&gt;
&lt;br /&gt;
Именно повторяющееся попарное суммирование на каждом уровне составляет основную часть вычислений. &lt;br /&gt;
В аппаратных реализациях ядром выступают параллельно работающие сумматоры, а в программных - повторяющаяся процедура сложения пар элементов массива.&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
[[File:Model.png|center|Описание изображения]]&lt;br /&gt;
Рис. 1 Диаграмма маршрутизации каскадной схемы суммирования&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4%D0%BD%D0%B0%D1%8F_%D1%81%D1%85%D0%B5%D0%BC%D0%B0_%D1%81%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=30036</id>
		<title>Участник:Bannikov Nikolay/Каскадная схема суммирования</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4%D0%BD%D0%B0%D1%8F_%D1%81%D1%85%D0%B5%D0%BC%D0%B0_%D1%81%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=30036"/>
		<updated>2025-11-19T01:29:57Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Каскадная схема суммирования&#039;&#039;&#039; представляет собой алгоритм поэтапного (многоуровневого) сложения нескольких числовых величин, организованных в каскадную структуру. Основная идея заключается в том, что входные данные (слагаемые) группируются и суммируются последовательно на каждом уровне каскада, а полученные промежуточные результаты передаются на следующий уровень для дальнейшего суммирования.&lt;br /&gt;
&lt;br /&gt;
Такая организация позволяет повысить быстродействие за счёт параллельного выполнения частичных сумм и уменьшения задержек при обработке больших массивов данных. Каскадная схема часто используется в цифровых вычислительных устройствах и системах обработки сигналов, где требуется эффективное выполнение операций сложения большого числа аргументов.&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
Пусть имеется набор входных данных: $$X = \{x_1,x_2,...,x_n\} $$&lt;br /&gt;
Необходимо найти их сумму: $$S = \sum_{i=1}^n x_i$$&lt;br /&gt;
В каскадной схеме процесс выполняется в несколько уровней. На каждом уровне производится суммирование попарных элементов предыдущего уровня.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
На первом уровне формируются частичные суммы $$y_{j}^{(1)} = x_{2j-1} + x_{2j}, \quad j = 1,2,...\frac{n}{2}$$&lt;br /&gt;
На втором уровне — суммы результатов первого уровня $$y_{k}^{(2)} = y_{2k-1}^{(1)} + y_{2k}^{(1)}, \quad k = 1,2,...\frac{n}{4}$$&lt;br /&gt;
И так далее, пока не останется одно значение — итоговая сумма $$S = y_1^{(m)}, \quad где \ m = \log_{2} n$$&lt;br /&gt;
===  Вычислительное ядро алгоритма ===&lt;br /&gt;
В каскадной схеме суммирования вычислительным ядром является операция попарного сложения элементов &lt;br /&gt;
на каждом уровне каскада. Именно эта часть алгоритма выполняется многократно и определяет основную &lt;br /&gt;
вычислительную нагрузку.&lt;br /&gt;
&lt;br /&gt;
На каждом уровне происходит одинаковая базовая операция: $$y=a+b$$&lt;br /&gt;
где a и b — либо исходные элементы, либо частичные суммы предыдущего уровня.&amp;lt;br&amp;gt;&lt;br /&gt;
Вычислительное ядро включает:&lt;br /&gt;
* Формирование пар чисел&lt;br /&gt;
* Выполнение операции их сложения&lt;br /&gt;
* Передачу полученных частичных сумм на следующий уровень&lt;br /&gt;
&lt;br /&gt;
Объем вычислительного ядра:&lt;br /&gt;
* Общее количество операций сложения: $n-1$&lt;br /&gt;
* Количество уровней каскада: $\log_{2} n$&lt;br /&gt;
* Максимальное количество операций на уровне: $\frac{n}{2}$&lt;br /&gt;
Ключевые характеристики ядра:&lt;br /&gt;
* Регулярная структура - все операции однотипны (бинарное сложение)&lt;br /&gt;
* Локальность данных - на каждом уровне вычисления используют только результаты с предыдущего уровня&lt;br /&gt;
* Параллелизм - операции в пределах одного уровня независимы и могут выполняться параллельно&lt;br /&gt;
&lt;br /&gt;
Именно повторяющееся попарное суммирование на каждом уровне составляет основную часть вычислений. &lt;br /&gt;
В аппаратных реализациях ядром выступают параллельно работающие сумматоры, а в программных - повторяющаяся процедура сложения пар элементов массива.&lt;br /&gt;
===  Макроструктура алгоритма ===&lt;br /&gt;
===  Схема реализации последовательного алгоритма ===&lt;br /&gt;
===  Последовательная сложность алгоритма ===&lt;br /&gt;
===  Информационный граф ===&lt;br /&gt;
[[File:Model.png|center|Описание изображения]]&lt;br /&gt;
Рис. 1 Диаграмма маршрутизации каскадной схемы суммирования&lt;br /&gt;
===  Ресурс параллелизма алгоритма ===&lt;br /&gt;
===  Входные и выходные данные алгоритма ===&lt;br /&gt;
===  Свойства алгоритма ===&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Model.png&amp;diff=30035</id>
		<title>Файл:Model.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Model.png&amp;diff=30035"/>
		<updated>2025-11-18T23:49:46Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Диаграмма маршрутизации каскадной схемы суммирования&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:111.png&amp;diff=30034</id>
		<title>Файл:111.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:111.png&amp;diff=30034"/>
		<updated>2025-11-18T23:44:56Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;схема&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:10.png&amp;diff=30033</id>
		<title>Файл:10.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:10.png&amp;diff=30033"/>
		<updated>2025-11-18T23:42:14Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Диаграмма маршрутизации&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:11.png&amp;diff=29963</id>
		<title>Файл:11.png</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:11.png&amp;diff=29963"/>
		<updated>2025-11-06T17:08:44Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Диаграмма маршрутизации&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
	<entry>
		<id>https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4%D0%BD%D0%B0%D1%8F_%D1%81%D1%85%D0%B5%D0%BC%D0%B0_%D1%81%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=29877</id>
		<title>Участник:Bannikov Nikolay/Каскадная схема суммирования</title>
		<link rel="alternate" type="text/html" href="https://xn--80aecvaldz.xn--80ahdrnmvk.xn--p1ai/w/ru/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Bannikov_Nikolay/%D0%9A%D0%B0%D1%81%D0%BA%D0%B0%D0%B4%D0%BD%D0%B0%D1%8F_%D1%81%D1%85%D0%B5%D0%BC%D0%B0_%D1%81%D1%83%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F&amp;diff=29877"/>
		<updated>2025-11-04T00:17:06Z</updated>

		<summary type="html">&lt;p&gt;Bannikov Nikolay: Новая страница: «== Свойства и структура алгоритма == === Общее описание алгоритма === &amp;#039;&amp;#039;&amp;#039;Каскадная схема сумми...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Свойства и структура алгоритма ==&lt;br /&gt;
=== Общее описание алгоритма ===&lt;br /&gt;
&#039;&#039;&#039;Каскадная схема суммирования&#039;&#039;&#039; представляет собой алгоритм поэтапного (многоуровневого) сложения нескольких числовых величин, организованных в каскадную структуру. Основная идея заключается в том, что входные данные (слагаемые) группируются и суммируются последовательно на каждом уровне каскада, а полученные промежуточные результаты передаются на следующий уровень для дальнейшего суммирования.&lt;br /&gt;
&lt;br /&gt;
Такая организация позволяет повысить быстродействие за счёт параллельного выполнения частичных сумм и уменьшения задержек при обработке больших массивов данных. Каскадная схема часто используется в цифровых вычислительных устройствах и системах обработки сигналов, где требуется эффективное выполнение операций сложения большого числа аргументов.&lt;br /&gt;
===  Математическое описание алгоритма ===&lt;br /&gt;
Пусть имеется набор входных данных: $$X = \{x_1,x_2,...,x_n\} $$&lt;br /&gt;
Необходимо найти их сумму: $$S = \sum_{i=1}^n x_i$$&lt;br /&gt;
В каскадной схеме процесс выполняется в несколько уровней. На каждом уровне производится суммирование попарных элементов предыдущего уровня.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
На первом уровне формируются частичные суммы $$y_{j}^{(1)} = x_{2j-1} + x_{2j}, \quad j = 1,2,...\frac{n}{2}$$&lt;br /&gt;
На втором уровне — суммы результатов первого уровня $$y_{k}^{(2)} = y_{2k-1}^{(1)} + y_{2k}^{(1)}, \quad k = 1,2,...\frac{n}{4}$$&lt;br /&gt;
И так далее, пока не останется одно значение — итоговая сумма $$S = y_1^{(m)}, \quad где \ m = \log_{2} n$$&lt;br /&gt;
== Программная реализация алгоритма ==&lt;br /&gt;
== Литература ==&lt;br /&gt;
# А.В.Старченко, В.Н.Берцун. Методы параллельных вычислений. Изд-во Том. ун-та, 2013. - 223 с. (Серия &amp;quot;Суперкомпьютерное образование&amp;quot;)&lt;/div&gt;</summary>
		<author><name>Bannikov Nikolay</name></author>
	</entry>
</feed>