Алгоритм Тоома — Кука
Алгоритм Тоома — Кука, иногда упоминаемый как Tоом-3 и названный именами Андрея Леоновича Тоома, предложившего новый алгоритм с низкой сложностью, и Стивена Кука, более ясно описавшего алгоритм, это алгоритм умножения больших чисел.
Если даны два больших числа a и b, Тоома — Кука разбивает a и b на k меньших частей каждое длиной l и осуществляет операции над частями. При росте k можно комбинировать часть операций умножения частей разбиения, сокращая тем самым общую сложность алгоритма. Умножение частей разбиения можно затем вычислить с помощью того же самого алгоритма Тоома — Кука рекурсивно. Термины «алгоритм Тоома-3» и «алгоритм Тоома — Кука» иногда ошибочно используются как синонимы, хотя Тоом-3 является лишь частным случаем алгоритма Тоома — Кука для k = 3.
Тоом-3 сокращает сложность с 9 умножений до 5 и работает за время . В общем случае Тоом-k работает за время , где , является временем, затрачиваемым на умножения подчастей, а c — время, затрачиваемое на сложения и умножение на малые константы [1]. Алгоритм Карацубы является частным случаем алгоритма Тоома — Кука, где число разбивается на две части. Он сокращает сложность с 4 умножений до 3, а потому работает за время . Обычное умножение в столбик эквивалентно Тоом-1 со сложностью .
Хотя степень e может быть установлена как можно близкой к 1 путём увеличения k, функция c, к сожалению, растёт очень быстро[1][2]. Скорость роста для смешанных схем Тоома — Кука оставалась открытой проблемой к 2005-му году[3]. Реализация, описанная Дональдом Кнутом добивается сложности [4].
За счёт накладных расходов алгоритм Тоома-Кука для малых чисел медленнее умножения в столбик и потому обычно использовался для множителей среднего размера, пока не был обнаружен асимптотически более быстрый алгоритм Шёнхаге — Штрассена (со сложностью .
Тоом описал свой алгоритм в 1963 году, а Кук опубликовал улучшенный (асимптотически эквивалентный) алгоритм в тезисах своей диссертации в 1966-м году[5].
Детали
В этой секции обсуждается работа алгоритма Тоома-k для любого заданного значения k и даётся упрощённое описание умножения Тоома — Кука многочленов, которое описал Марко Бодрато[6]. Алгоритм имеет пять основных шагов:
В типичной интерпретации больших чисел каждое целое представляется как последовательность цифр в позиционной системе счисления, где основанием счисления берётся некоторое (обычно большое) значение b. В нашем примере мы используем , так что каждая цифра соответствует группе из четырёх десятичных цифр (в реализации в компьютере в качестве b обычно берётся степень двойки). Скажем, нужно перемножить два числа
m = 12 3456 7890 1234 5678 9012 n = 9 8765 4321 9876 5432 1098.
Они много меньше, чем обычно обрабатываются алгоритмом Тоома — Кука, но они здесь иллюстрируют алгоритм.
Разбиение
Первым шагом является выбор основания счисления , так что число цифр как у числа m, так и у числа n по основанию B не превосходит k (например, 3 в Тоом-3). Обычно i задаётся выражением
В нашем примере мы будем использовать Тоом-3, так что мы выбираем . Теперь мы разбиваем m и n по их основанию счисления B на цифры :
Мы будем использовать эти цифры как коэффициенты в многочленах p и q степени (k − 1), со свойствами и :
После введения этих многочленов получаем, что если мы вычислим произведение , то ответом задачи будет .
В случае, когда перемножаемые числа имеют разные размеры, полезно использовать разные значения k для m и n, которые мы будем обозначать и . Например, алгоритм «Тоом-2.5» относится к алгоритму Тоома-Кука с и . В этом случае i в обычно выбирается по выражению
Вычисление в точках
Подход Тоома — Кука вычисления произведения многочленов обычен. Заметим, что многочлен степени d единственным образом определяется точками (например, прямая — это многочлен степени 1 и определяется двумя точками). Идеей является вычисление p(•) и q(•) в различных точках. Затем осуществляется произведение значений в этих точках, чтобы получить значения произведения многочленов. Наконец, интерполируем полученные значения для получения коэффициентов многочлена.
Поскольку , нам нужно точек для получения коечного результата. Назовём его d. В случае Тоом-3 . Алгоритм будет работать независимо от того, какие точки были выбраны (с несколькими небольшими исключениями — см. требование обратимости матрицы в разделе Интерполяция), но для упрощения алгоритма лучше использовать небольшие значения типа 0, 1, −1 и −2.
Одна необычная точка, которая часто используется, это бесконечность, то есть . Чтобы «вычислить» многочлен p на бесконечности, берут предел при стремлении x к бесконечности. Следовательно, всегда равно значению старшего коэффициента (в примере выше — коэффициента ).
В нашем примере Тоом-3 мы используем точки 0, 1, −1, −2 и . Этот выбор упрощает вычисление в точках и даёт формулы:
И аналогично для q. В нашем примере, значения, которые мы получаем, равны:
= = 56789012 = 56789012 = = = 135813702 = = = −21988766 = = = −100519632 = = 123456 = 123456 = = 54321098 = 54321098 = = = 97639739 = = = 11199987 = = = −31723594 = = 98765 = 98765.
Как видно, эти значения могут быть отрицательными.
Для дальнейших объяснений полезно рассматривать этот процесс вычисления в точках как умножение матрицы на вектор справа, где каждая строка матрицы содержит степени одной из выбранных точек, а вектор содержит коэффициенты многочлена:
Размерности матриц равны для p и для q. Строка для значения бесконечность имеет нулевые значения за исключением последнего столбца, в котором стоит 1.
Более быстрое вычисление значений
Вычисление значений в точках может быть выполнено быстрее, чем указано в приведённых выше формулах. Число элементарных операций (сложение/вычитание) может быть сокращено. Последовательность операций, придуманная Бодрато[6] для Тоом-3, показана здесь для первого операнда (многочлена p):
= 56789012 + 123456 = 56912468 = = 56789012 = 56789012 = = 56912468 + 78901234 = 135813702 = = 56912468 − 78901234 = −21988766 = = = − 100519632 = = 123456 = 123456.
Эта последовательность требует пять операций сложения/вычитания, на единицу меньше, чем при прямом вычислении. Более того, нам не нужно умножать на 4 при вычислении p(−2).
Поточечное умножение
В отличие от умножения многочленов p(•) и q(•) умножение вычисленных значений p(a) и q(a) просто сводится к умножению целых — более простого варианта исходной задачи. Мы рекурсивно используем нашу процедуру умножения для вычисления каждой пары значений в точках. В практических реализациях, когда операнды становятся меньше, алгоритм сводится к умножению в столбик. Если r — произведение многочленов, в нашем примере мы имеем:
= = = 3084841486175176 = = = 13260814415903778 = = = −246273893346042 ) = = = 3188843994597408 = = = 12193131840.
Как видим, эти значения могут быть отрицательными. Для достаточно больших чисел это наиболее дорогой шаг, единственный шаг, не зависящий линейно от размеров m и n.
Интерполяция
Это наиболее сложный шаг, обратный шагу вычисления в точках — если даны наши d точек произведения многочленов r(•), мы должны вычислить его коэффициенты. Другими словами, мы должны решить матричное уравнение с вектором в правой части:
Эта матрица строится так же, как и на шаге вычисления значений многочлена в точках, за исключением, что матрица имеет размер d × d. Мы можем решить это уравнение с помощью метода Гаусса (метода исключений), но это будет очень дорого. Вместо этого мы используем факт, что используемые для вычисления значений точки выбраны специальным образом, позволяющим легко вычислить обратную матрицу (см. также Матрица Вандермонда), а тогда
Теперь остаётся лишь вычислить произведение матрицы на вектор. Хотя матрица содержит дроби, результирующие коэффициенты будут целыми числами, так что вычисления можно вести в целочисленной арифметике путём сложения, вычитания и умножения/деления на маленькие константы. Здесь основной задачей является поиск эффективной последовательности операций, позволяющей вычислить произведение матрицы на вектор. Одну такую последовательность дал Бодрато[6] для Тоом-3 и она для нашего примера следующая:
= 3084841486175176 = 12193131840 = (3188843994597408 − 13260814415903778)/3 = −3357323473768790 = = 6753544154624910 = = −3331115379521218 = = 13128433387466 = −3331115379521218 + 6753544154624910 − 12193131840 = 3422416581971852 = 6753544154624910 − 13128433387466 = 6740415721237444.
Мы теперь знаем произведение r наших многочленов:
Если бы мы использовали другие или выбрали другие точки для вычисления значений, матрица, а тогда и стратегия интерполяции, изменилась бы, но это не зависит от входных данных, а потому алгоритм может быть зашит «в железе» для любых данных параметров.
Рекомпозиция
Наконец, мы вычисляем r(B) для получения конечного результата. Это выполняется напрямую, поскольку B является степенью b, а потому умножение на степени B является сдвигом всего числа на целое число знаков основания b. В нашем примере и .
3084 8414 8617 5176 6740 4157 2123 7444 3422 4165 8197 1852 13 1284 3338 7466 + 121 9313 1840 121 9326 3124 6761 1632 4937 6009 5208 5858 8617 5176
И это, фактически, произведение 1234567890123456789012 иd 987654321987654321098.
Матрицы интерполяции для различных значений k
Здесь мы приведём матрицы интерполяции для нескольких различных малых значений и .
Тоом −1
Тоом-1 () требует вычисления в одной точке, здесь выбирается 0. Алгоритм вырождается в умножение в столбик с единичной матрицей интерполяции:
Тоом-1.5
Тоом-1.5 () требует две точки, здесь выбраны 0 и . Матрица интерполяции тогда равна единичной матрице:
Алгоритм также вырождается в умножение в столбик — оба коэффициента одного множителя умножается на один коэффициент другого множителя.
Тоом-2
Тоом-2 () требует трёх точек, здесь выбраны 0, 1 и . Алгоритм получается тем же, что и алгоритм Карацубы с матрицей интерполяции
Тоом-2.5
Тоом-2.5 ( требует 4 точки, здесь выбраны 0, 1, −1 и . Алгоритм тогда имеет матрицу интерполяции:
Примечания
- Knuth, 1997, с. 296.
- Crandall, Pomerance, 2005, с. 474.
- Crandall, Pomerance, 2005, с. 536.
- Knuth, 1997, с. 302.
- Positive Results, chapter III of Stephen A. Cook: On the Minimum Computation Time of Functions.
- Bodrato, 2007, с. 116–133.
Литература
- D. Knuth. Section 4.3.3.A: Digital methods // The Art of Computer Programming. — Third Edition. — Addison-Wesley, 1997. — Т. 2. — С. 294.
- Кнут Д.Э. Искусство программирования. Получисленные алгоритмы. — 2019. — Т. 2. — ISBN 978-5-907144-15-6.
- R. Crandall, C. Pomerance. Section 9.5.1: Karatsuba and Toom–Cook methods // Prime Numbers – A Computational Perspective. — Second Edition. — Springer, 2005. — С. 473.
- Ричард Крэндалл, Карл Померанс. Простые числа. Криптографические и вычислительные аспекты. — Москва: Либроком, 2011. — ISBN 978-5-397-02060-2.
- M. Bodrato. Toward Optimal Toom–Cook Multiplication for Univariate and Multivariate Polynomials in Characteristic 2 and 0 // Arithmetic of Finite Fields. — Springer, 2007. — Т. 4547. — (LNCS).