- •Длинная арифметика
- •Введение
- •1. Способы представления «длинных» чисел
- •2. Ввод-вывод "длинных" чисел
- •3. Сложение двух «длинных» чисел
- •4. Умножение «длинного» числа на «короткое»
- •5. Умножение «длинного» числа на «длинное»
- •6. Рекурсивный алгоритм умножения
- •7. Вычитание двух “длинных” чисел с учетом сдвига
- •8. Деление «короткого» числа на «короткое» столбиком
- •9. Деление «длинного» числа на «короткое» нацело с остатком
- •10. Сравнение двух “длинных” чисел
- •11. Задачи с решениями
- •12. Контрольные вопросы и упражнения
9. Деление «длинного» числа на «короткое» нацело с остатком
Решение этой задачи мало отличается от предыдущей, поэтому дадим лишь некоторые пояснения к приведенным ниже программам.
Так как делить на этот раз мы будем «длинное» число, входные данные удобнее представлять в файле. Входным файлом в данной задаче является файл input.txt, а выходным — output.txt.
Делимое при вводе из файла в подпрограмме ReadData запоминается в массиве а (в первом элементе старшая цифра), делитель — в целой переменной b, а целую часть результата будем получать в массиве с (в первом элементе также находится старшая цифра).
Нулевые элементы массивов a и с содержат значения текущей длины этих массивов (а[0] — заполняется при считывании делимого из файла, а с[0] — при получении целой части результата). Так как делитель у нас является числом «коротким», а остаток от деления всегда меньше делителя, то для его получения массив не нужен.
Туре
Abyte=array[0..32000] of byte;
Var
а,с: AByte;
b,p: longint;
Procedure ReadData;
var
ch:char;
begin
Assign(input,'input.txt');
Reset(input);
a[0] := 0; {длина числа А}
c[0] := 0; {длина числа С}
while not SeekEoln do {пока не достигнут конец строки}
begin
read(ch);
inc (a[0]); {перевод символа в цифру}
а[а[0]]:=ord(ch)-ord('0')
end;
readln;
read(b);
Close(input)
end;
Procedure Count;
var
ptr: word;
begin
p:=0;
ptr:=1;
while (p<b) and (ptr<=a[0]> do
begin
p:=p*10+a[ptr];
inc(ptr)
end;
inc(c[0]); {с[0] — длина целой части частного}
с[с[0]] := р div b; {определили первую цифру частного}
р := р mod b;
while ptr<=a[0] do
{определяем остальные цифры частного}
begin
р:=p*10+а[ptr];
inc(ptr);
inc(c[0]);
c[c[0]] := p div b;
p := p mod b
end
end;
Procedure WriteResult;
var
i: word;
begin
assign(Output,'Output.txt');
rewrite(Output);
for i:=l to c[0] do write (с[i]); {печатаем целую часть частного от деления}
writeln;
writeln(p); {печатаем остаток от деления}
end;
{Основная программа}
Begin
ReadData;
Count;
WriteResult
End.
10. Сравнение двух “длинных” чисел
Сравнения "длинных" чисел похожи на сравнения простых чисел и не представляют большой сложности. Рекомендуется реализации операций сравнения изучить самостоятельно.
Приведем примеры реализаций операций сравнения для “длинных” чисел.
Function Eq (A, B: TLong): Boolean;
Var i: Integer;
Begin
Eq:=False;
If A[0]<>B[0] Then Exit {если числа не равны, то выходим из программы}
Else
Begin
{иначе, пока выполняется условие, что каждая цифра значения элемента A[i] равны каждой цифре элемента B[i], значение i увеличиваем на 1, итак пока не будут проверены массивы до конца}
i:=1;
While (i<=A[0]) And (A[i]=B[i]) Do Inc (i);
Eq:= (i=A[0]+1);
End;
End;
Реализация функции A > B также прозрачна.
Function More (A, B: TLong): Boolean;
Var i:Integer;
Begin
{сравниваем длины чисел А и В (мы еще говорили, что в A[0] элементе массива хранится длина числа}
If A[0]<B[0] Then More:= False
Else
If A[0]>B[0] Then More:= True
Else
Begin
i:= A[0];
While (i>0) And (A[i]=B[i]) Do Dec (i);
{проверяем каждый элемент массива сравнивая их друг с другом}
If i=0 Then More:=False
Else
If A[i]>B[i] Then More:=True
Else More:=False;
End;
End;
Остальные функции реализуются через функции Eq и More.
Function Less (A, B:TLong):Boolean; {A<B}
Begin
Less:=Not (More (A, B) Or Eq (A, B));
End;
Function
More_Eq (A, B:TLong):Boolean; {A
B}
Begin
More_Eq:=More (A, B) Or Eq (A, B);
End;
И,
наконец, последняя функция А
В.
Function Less_Eq (A, B:TLong):Boolean;
Begin
Less_Eq:=Not (More (A, B) );
End;
Для самостоятельного решения может быть предложена следующая, более сложная, задача.
Требуется разработать функцию, которая выдает 0, если А больше В, если А меньше В, и 2 при равенстве чисел. Но сравнение должно быть выполнено с учетом сдвига.
О чем идет речь? Поясним на примере. Пусть А равно 56784, а В - 634. При сдвиге числа В на 2 позиции влево функция должна сказать, что В больше А, без сдвига, что А больше В.
Другой пример. При А равном 56700, а В - 567 и сдвиге 2 функция должна “сказать”, что числа равны.
Решение иметь следующий вид:
Function More (Const A, B:TLong; Const sdvig:Integer):Byte;
Var i:Integer;
Begin
If A[0]>(B[0]+sdvig) Then More:=0
Else
If A[0]<(B[0]+sdvig) Then More:=1
Else
Begin
i:=A[0];
While (i>sdvig)And(A[i]=B[i-sdvig]) Do Dec (i);
More:=0;
If i=sdvig
Then
Begin
{совпадение чисел с учетом сдвига}
For i:=1 To sdvig Do
If A[i] > 0 Then Exit;
More:=2; {числа равны, “хвост” числа А равен нулю}
End
Else More:=Byte (A[i] < B[i-sdvig]);
End;
End;
