Арифметика многократной точности (длинная арифметика) Бирюков С. В.
План лекции: ü Почему необходимо использовать длинную арифметику ü Ввод и представление длинных чисел ü Вывод длинных чисел ü Сравнение длинных чисел ü Сложение вычитание длинных чисел ü Умножение длинного числа на короткое ü Умножение двух длинных чисел ü Деление длинного числа на короткое ü Деление длинных чисел ü Извлечение квадратного корня из длинного числа ü Алгоритм быстрого деления чисел ü Алгоритм быстрого умножения чисел
Почему необходимо использовать длинную арифметику: z Во всех современных языках программирования реализованы типы данных для работы с достаточно большими вещественными и целыми числами. z Самый «большой» тип данных из доступных нам (С++ и Pascal) - 8 байтовое целое число – 2^64 (около 9*10^18). z 2^64 – это очень много. Просто чтобы сосчитать до него с помощью среднего компьютера, потребуется около 200000 часов. z Такого типа данных хватает практически всегда, если конечно речь не идет об олимпиадных задачах . z Не спасают и вещественные типы данных так как представляют число лишь с некоторой точностью. Это понятно из их представления в памяти ЭВМ. z Например, тип double имеет диапазон значений (-10 Е 307. . 10 Е 308). Однако он может хранить лишь несколько старших разрядов числа и его порядок. Именно поэтому он не пригоден в тех задачах, где необходим точный результат. z. Значит, необходимо самостоятельно реализовать нужные операции.
Представление длинных чисел: z Прежде всего, определимся как и в какой структуре данных будут храниться числа. z Любое число Х системе счисления по основанию В можно представить как Например, в привычной нам В=10: 4059 = 9*1 + 5*10 + 0*100 + 4 *1000 z То есть мы можем хранить каждую цифру в отдельном элементе массива и выполнять операции отдельно над цифрами. z Кроме того, мы можем выбрать основание системы максимально большим (например 10^9, вы можете выбрать любую), чтобы минимизировать число цифр, и соответственно число операций. z Будем хранить число как бы «наоборот» . Менее значимые разряды - в младших элементах массива. В нулевом элементе хранится длина числа. Х = 34029093267562367543543; В = 10^9 3 367543543 93267562 0 1 2 34029 3
Ввод длинных чисел: z Обычно длинные числа не вводятся непосредственно во входных данных к задаче, а формируются в процессе вычислений. Однако если нужно ввести длинное число, его нужно корректно расположить в структуре (в соответствии с принятой системой представления) z Будем использовать следующие обозначения во всех последующих процедурах: typedef long Big. Int[100]; Big. Int A, B, C; long Osn=100000; long len. Osn=9; z Идея ввода: Ввод> 34029|093267562|367543543| 3 367543543 93267562 0 1 2 34029 3
Ввод длинных чисел: void Big. Int. Input(Big. Int A){ char in. Str[200]; char buf[10]; int i, j, start. Pos, end. Pos; Init(A, 0); scanf("%s", in. Str); A[0]=strlen(in. Str)/len. Osn; if (strlen(in. Str)%len. Osn != 0) A[0]++; start. Pos=strlen(in. Str)-len. Osn; end. Pos=strlen(in. Str); for (i=1; i<=A[0]; i++){ if (start. Pos<0) start. Pos=0; for (j=0; j<(end. Pos-start. Pos); j++) buf[j]=in. Str[start. Pos+j]; buf[end. Pos-start. Pos]='