Выбрать главу

Умножение длинного на короткое. Исходными данными служат длинное число и обычное число, по величине равное 64 или меньше; результатом должно быть их произведение в виде длинного числа. Эту операцию можно выполнять справа налево, как вручную.

Деление длинного на короткое. Исходными данными служат длинное число и обычное число, не превосходящее 64, а результатом должно быть длинное частное от деления длинного числа на короткое. Эту операцию можно выполнять слева направо, как это делается вручную.

Перевод. Исходными данными для этой подпрограммы является длинное число, а результатом должно быть то же число, записанное в десятичной системе на некотором устройстве вывода. При появлении потребности в более сложном выводе можно разработать более детальные спецификации подпрограммы перевода.

Инструментовка. В качестве языка реализации сразу же приходит на ум Паскаль: в этом языке хорошие структуры данных и управляющие структуры. Однако Паскаль не позволяет легко переводить внутреннее битовое представление в битовые цепочки, доступные программисту, и обратно. Языки более низкого уровня — BLISS и XPL — обеспечивают более прямой доступ к ЭВМ за счет некоторой потери выразительности и надежности. Хорошая защищенность языков высокого уровня и доступ к машинному представлению сочетаются в PL/I, но обычно за это приходится расплачиваться временем выполнения. Для данного этюда важно также время, которое вы потеряете, пытаясь постичь некоторые весьма изощренные возможности PL/I. Интересной представляется реализация на Траке, поскольку в этом случае автоматически решается задача распределения памяти для цепочек.

Длительность исполнения. Одному исполнителю на 5 недель или двум на 3 недели.

Развитие темы. Как только у нас появляется арифметика высокой точности, сразу же возникает много интересных задач. Одна из них — точное вычисление числа e. Ряд для e особенно прост:

где 0! = 1. Любой студент, изучающий математический анализ, может придумать еще очень много рядов и констант.

* Партия переводчика. Можно существенно сократить как время работы программ, так и время их написания, если, не послушавшись автора, создать набор специализированных программ для вычисления π. Анализируя ряд для π, мы видим, что его вычисление требует всего двух программ высокой точности. Это программа сложения-вычитания длинных чисел (сложение и вычитание настолько похожи, что их можко рассматривать как одно действие) и программа деления длинного числа на короткое, т. е. на представимое в виде обычного целого числа. Эти действия, выполняемые классическими ручными методами, занимают лишь линейное по n время.

Кроме того, имеет смысл хранить длинные числа не в двоичной системе счисления, а в десятичной (конечно, не по одной цифре в элементе массива, а по столько цифр, сколько помещается в обычном целом числе). При этом отпадает необходимость в программе перевода. Теперь арифметические программы могут работать несколько медленнее (но вовсе не обязательно; далеко не все компиляторы используют команды сдвига для умножения и деления на степени двойки), тем не менее в целом можно получить выигрыш в скорости, поскольку время работы алгоритма перевода длинных чисел из двоичной системы в десятичную (описанного у Кнута) пропорционально n², т. е. того же порядка, что и время всех остальных вычислений.

С помощью лишь этих программ сложения и деления можно вычислить многие математические константы: π, e, √2, ∛2, ln 2 и т. д. Реализация такого усеченного варианта потребует, вероятно, не более одной человеко-недели. Сложные динамические структуры данных уже не потребуются; у нас будет всего два-три длинных числа известного размера, для представления которых вполне подойдут массивы Фортрана.

Литература

Ахо, Хопкрофт, Ульман (Aha А. V., Haperoft J. E., Ullman J. D.). The Design and Analysis of Computer Algorithms. Addison-Wesley, Reading, MA, 1974. Section 8.2, pp. 279–286. [Имеется перевод: Ахо А., Хопкрофт Дж., Ульман Дж. Построение и анализ вычислительных алгоритмов. — М.: Мир, 1979, § 8.2, с. 313–320.]

Мы почерпнули алгоритм умножения у Кнута, а алгоритм деления — у Ахо, Хопкрофта и Ульмана; оба алгоритма переработаны для наших целей Эти книги содержат подробную информацию по основам и детальный анализ алгоритмов, включая оценки сложности. Описываются также альтернативные алгоритмы умножения, основанные на быстром преобразовании Фурье[35].

Брент (Brent R. P.). A FORTRAN Multiple-Precision Arithmetic Package, Department of Computer Science, Carnegie-Mellon University, May 1976.

Брент описывает пакет подпрограмм для арифметических действий с высокой точностью, написанных на переносимом, машинно-независимом Фортране. Благодаря включенной в книгу библиографии, вы сможете найти другие работы в этой области. В пакете, предложенном Брентом, не используется алгоритм Тоома—Кука, и автор объясняет почему.

вернуться

35

Эти алгоритмы для очень длинных чисел работают еще быстрее алгоритма Тоома—Кука, затрачивая на умножение n-разрядных чисел время, пропорциональное n log n log log n — Прим. перев.