Попарное суммирование
В численном анализе , попарное суммирование также называемое каскадным суммированием , представляет собой метод суммирования последовательности конечной точности чисел с плавающей запятой , который существенно уменьшает накопленную ошибку округления по сравнению с наивным накоплением суммы последовательно. [1] Хотя существуют и другие методы, такие как суммирование Кахана , которые обычно имеют еще меньшие ошибки округления, попарное суммирование почти так же хорошо (отличается только логарифмическим коэффициентом), но требует гораздо меньших вычислительных затрат — его можно реализовать так, чтобы получить почти та же стоимость (и точно такое же количество арифметических операций), что и простое суммирование.
В частности, попарное суммирование последовательности из n чисел x n осуществляется путем рекурсивного разбиения последовательности на две половины, суммирования каждой половины и сложения двух сумм: алгоритм «разделяй и властвуй» . Ошибки округления в худшем случае растут асимптотически не более чем на O (ε log n ), где ε — точность машины (при условии фиксированного числа обусловленности , как обсуждается ниже). [1] Для сравнения, наивный метод последовательного накопления суммы (добавление каждого x i по одному для i = 1, ..., n ) имеет ошибки округления, которые в худшем случае растут как O (ε n ). [1] Суммирование Кахана имеет ошибку в худшем случае примерно O (ε), независимую от n , но требует в несколько раз больше арифметических операций. [1] Если ошибки округления случайны и, в частности, имеют случайные знаки, то они образуют случайное блуждание и рост ошибки сводится в среднем к для попарного суммирования. [2]
Очень похожая рекурсивная структура суммирования встречается во многих алгоритмах быстрого преобразования Фурье (БПФ) и отвечает за такое же медленное накопление округления этих БПФ. [2] [3]
Алгоритм
[ редактировать ]В псевдокоде алгоритм попарного суммирования массива x длины n можно записать ≥ 0:
s = pairwise(x[1...n]) if n ≤ N base case: naive summation for a sufficiently small array s = 0 for i = 1 to n s = s + x[i] else divide and conquer: recursively sum two halves of the array m = floor(n / 2) s = pairwise(x[1...m]) + pairwise(x[m+1...n]) end if
Для некоторого достаточно малого N этот алгоритм переключается на простое суммирование на основе циклов в качестве базового случая , граница ошибки которого равна O(Nε). [4] Вся сумма имеет ошибку наихудшего случая, которая асимптотически растет как O (ε log n ) для больших n и заданного числа обусловленности (см. ниже).
В алгоритме такого типа (как и в алгоритмах «разделяй и властвуй» вообще) [5] ), желательно использовать больший базовый вариант, чтобы амортизировать накладные расходы на рекурсию. Если N = 1, то для каждого ввода существует примерно один рекурсивный вызов подпрограммы, но в более общем случае существует один рекурсивный вызов для (примерно) каждых N /2 входных данных, если рекурсия останавливается ровно на n = N . Сделав N достаточно большим, накладные расходы на рекурсию можно сделать незначительными (именно этот метод большого базового случая для рекурсивного суммирования используется высокопроизводительными реализациями БПФ). [3] ).
Независимо от N , всего выполняется ровно n -1 сложений, так же, как и при простом суммировании, поэтому, если накладные расходы на рекурсию пренебрежимо малы, то попарное суммирование имеет по существу те же вычислительные затраты, что и при простом суммировании.
Вариант этой идеи состоит в том, чтобы разбить сумму на b блоков на каждом рекурсивном этапе, рекурсивно суммировать каждый блок, а затем суммировать результаты, что авторы окрестили алгоритмом «суперблока». [6] Вышеупомянутый парный алгоритм соответствует b за исключением последнего этапа, который равен b = N. = 2 для каждого этапа ,
Точность
[ редактировать ]Предположим, что кто-то суммирует n значений x i , для i = 1, ..., n . Точная сумма:
(вычислено с бесконечной точностью).
При попарном суммировании для базового случая N = 1 вместо этого получается , где ошибка ограничено сверху: [1]
где ε — машинная точность используемой арифметики (например, ε ≈ 10 −16 для стандартной двойной точности с плавающей запятой). Обычно интересующей величиной является относительная ошибка , который, следовательно, ограничен сверху:
В выражении для оценки относительной ошибки дробь (Σ| x i |/|Σ x i |) является числом обусловленности задачи суммирования. По сути, число обусловленности представляет собой внутреннюю чувствительность задачи суммирования к ошибкам, независимо от того, как оно вычисляется. [7] Относительная граница ошибки для каждого ( обратно стабильного ) метода суммирования с использованием фиксированного алгоритма с фиксированной точностью (т.е. не тех, которые используют арифметику произвольной точности или алгоритмов, требования к памяти и времени которых меняются в зависимости от данных), пропорциональна этому числу обусловленности. . [1] Плохо обусловленная задача суммирования — это задача, в которой это отношение велико, и в этом случае даже попарное суммирование может иметь большую относительную ошибку. Например, если слагаемые x i представляют собой некоррелированные случайные числа с нулевым средним значением, сумма представляет собой случайное блуждание , и число обусловленности будет расти пропорционально . С другой стороны, для случайных входных данных с ненулевым значением число обусловленности асимптотируется до конечной константы как . Если все входные данные неотрицательны , то номер условия равен 1.
Обратите внимание, что на практике знаменатель фактически равен 1, поскольку намного меньше 1, пока n не станет порядка 2 1/е , что составляет примерно 10 10 15 в двойной точности.
Для сравнения, относительная ошибка, связанная с простым суммированием (простым последовательным добавлением чисел и округлением на каждом шаге), растет как умноженное на число условий. [1] На практике гораздо более вероятно, что ошибки округления имеют случайный знак с нулевым средним значением и образуют случайное блуждание; в этом случае наивное суммирование имеет среднеквадратичную относительную ошибку, которая растет как а попарное суммирование имеет ошибку, которая растет с ростом в среднем. [2]
Реализации программного обеспечения
[ редактировать ]Попарное суммирование — это алгоритм суммирования по умолчанию в NumPy. [8] и технико-вычислительный язык Julia , [9] где в обоих случаях было обнаружено, что скорость его сравнима с простым суммированием (благодаря использованию большого базового случая).
Другие реализации программного обеспечения включают библиотеку HPCsharp. [10] для языка C# и суммирования стандартной библиотеки [11] в Д.
Ссылки
[ редактировать ]- ^ Перейти обратно: а б с д и ж г Хайэм, Николас Дж. (1993), «Точность суммирования с плавающей запятой», SIAM Journal on Scientific Computing , 14 (4): 783–799, CiteSeerX 10.1.1.43.3535 , doi : 10.1137/0914050
- ^ Перейти обратно: а б с Манфреда Таше и Хансмартина Цойнера Справочник по аналитически-вычислительным методам в прикладной математике Бока-Ратон, Флорида: CRC Press, 2000).
- ^ Перейти обратно: а б С. Г. Джонсон и М. Фриго, « Реализация БПФ на практике» , в книге «Быстрые преобразования Фурье» , под редакцией К. Сидни Берруса (2008).
- ^ Хайэм, Николас (2002). Точность и устойчивость численных алгоритмов (2-е изд.) . СИАМ. стр. 81–82.
- ^ Раду Ругина и Мартин Ринар, « Развертывание рекурсии для программ «разделяй и властвуй» ,» в книге «Языки и компиляторы для параллельных вычислений» , глава 3, стр. 34–48. Конспекты лекций по информатике, том. 2017 (Берлин: Springer, 2001).
- ^ Энтони М. Кастальдо, Р. Клинт Уэйли и Энтони Т. Хронопулос, «Уменьшение ошибок с плавающей запятой в скалярном произведении с использованием семейства алгоритмов суперблока», SIAM J. Sci. Вычислить. , том. 32, стр. 1156–1174 (2008).
- ^ Л. Н. Трефетен и Д. Бау, Численная линейная алгебра (SIAM: Филадельфия, 1997).
- ^ ENH: реализация попарного суммирования , запрос на извлечение github.com/numpy/numpy № 3685 (сентябрь 2013 г.).
- ^ RFC: используйте попарное суммирование для sum, cumsum и cumprod , запрос на извлечение github.com/JuliaLang/julia № 4039 (август 2013 г.).
- ^ https://github.com/DragonSpit/HPCsharp Пакет HPCsharp nuget высокопроизводительных алгоритмов C#.
- ^ «std.algorithm.iteration — язык программирования D» . dlang.org . Проверено 23 апреля 2021 г.