четверг, 8 января 2009 г.

О выполнении арифметических операций с длинными отрицательными числами

Спонсор реферата - сайт юмора и анекдотов, хохочите до упаду!

В работе [1] описаны арифметические действия с положительными длинными числами. Цель статьи заключается в том, чтобы изменить этот материал и для работы с отрицательными длинными числами.
Основные моменты логики программы:
Ввод данных:
Возможно считывание данных, как с клавиатуры, так и из файла. Данные считываются посимвольно и записываются в массив.
Считывая первый символ, мы смотрим, не является ли он «-». Если так то мы записываем его в переменную Sign(:Integer).Read(ch);If ch='-' Then Begin Sign:=1; Read(ch) End Else Sign:=0;
Далее воспользуемся процедурой ReadLong(Var A:TLong);
Затем после последнего разряда в массиве А мы ставим знак. A[A[0]+1]:=Sign;
Вывод данных:
Возможен вывод, как в файл, так и на экран. В процедуре WriteLong(Const A:TLong) учитываем знак в A[0]+1 разряде.
Перевод чисел в дополнительный код:
Перевод числа в дополнительный код (Procedure Add_cod(Var A:TLong);) является важной процедурой для сложения отрицательных чисел и считается математически обоснованным и теоретически доказанным шагом. Состоит он в следующем:
Каждой цифре числа присваиваем значение разности максимальной возможной цифры (в данной системе счисления) и значения цифры.For i:=1 To A[0] Do A[i]:=(Osn-1)-A[i]; {*где Osn-1 максимальная цифра в Osn-чной системе счисления*}
К полученному числу мы прибавляем 1.A[1]:=A[1]+1;For i:=1 To A[0] Do Begin {*Производим возможный перенос 1 в другие разряды *} A[i+1]:=A[i+1]+(A[i]) Div Osn; A[i]:=(A[i]) Mod Osn;End;
Кроме того, для нашей программы мы должны внимательно смотреть за знаком. То есть если значение знака четное, то число положительное, иначе оно отрицательное.A[A[0]+1]:=A[A[0]+1] Mod 2;
Замечание: в пунктах 3.a и 3.b мы абсолютно не касаемся знакового разряда.
Выравнивание длин чисел:
Так как числа у нас задаются с плавающей длинной, то перед выполнением сложения или вычитания необходимо выровнять их длину.
Procedure Leveling_length(Var A,B:TLong);
Var k,Sign:Integer;
Begin
If A[0]>B[0] Then k:=A[0] Else k:=B[0]; Inc(k); {*Так как данная процедура необходима только при сложении и вычитании, мы умышленно увеличиваем размерность чисел на 1 разряд, оставляя его пустым, иначе в процессе сложения или вычитания может произойти «непроизвольная смена знака»*}
Sign:=A[A[0]+1]; A[A[0]+1]:=0; A[0]:=k; A[A[0]+1]:=Sign;
Sign:=B[B[0]+1]; B[B[0]+1]:=0; B[0]:=k; B[B[0]+1]:=Sign;
End;
Суммирование:
Используем процедуру Summ(Const A,B:TLong; Var C:TLong);Однако суммируем не до последнего разряда, а до следующего, то есть мы складываем и знаковые разряды!!!
Длинна результата должна строго совпадать с первым или вторым числом.
Сложение:
Leveling_length(A,B);
If A[A[0]+1]<>0 Then Add_cod(A); {*Если число отрицательное мы переводим его в дополнительный код*}
If B[B[0]+1]<>0 Then Add_cod(B);
Summ(A,B,C);
If C[C[0]+1]<>0 Then Add_cod(C);
Вычитание:
Leveling_length(A,B);
If A[A[0]+1]<>0 Then Add_cod(A); {*Если число отрицательное мы переводим его в дополнительный код*}
If B[B[0]+1]<>0 Then Add_cod(B);
Inc(B[B[0]+1]); {*Переводим в дополнительный код, не спрашивая знака*}
Add_cod(B);
Summ(A,B,C);
If C[C[0]+1]<>0 Then Add_cod(C);
Длину результата можно подровнять:
Procedure Justification(Var A:TLong);)
Var Sign:byte;
i:Integer;
Begin
Sign:=A[A[0]+1];
A[A[0]+1]:=0;
i:=A[0];
While (i>1) And (A[i]=0) Do Dec(i); {*В числе все равно должен быть хотя бы 1 разряд*}
A[0]:=i;
A[A[0]+1]:=Sign;
End;
Функция больше возвращает истину или ложь:
Function More(Const A,B:TLong):Boolean; Var i:Integer; p:Boolean; Begin Case (A[A[0]+1] Xor B[B[0]+1]) Of {*Учитываем знак*} 0:Case A[A[0]+1] Of {*Сравниваем положительные*} 0:If A[0]>B[0] Then p:=True Else If A[0]0)And(A[i]=B[i])Do Dec(i); If (A[i]>B[i])And(i>0) Then p:=True Else p:=False; End; 1:If A[0]B[0] Then p:=False Else Begin i:=A[0]; While (i>0)And(A[i]=B[i])Do Dec(i); If (A[i]0) Then p:=True Else p:=False; End; End; 1:If A[A[0]+1]=0 Then p:=True Else p:=False; End; More:=p; End;
Функция равенства аналогична приведенной в [1].
Процедура произведение «длинного» на «длинное» немного исправленная:
Procedure MulLong(A,B:TLong; Var C:TLong); Var Sign,i,j:Integer; Begin Sign:=A[A[0]+1] Xor B[B[0]+1]; A[A[0]+1]:=0; B[B[0]+1]:=0; {*Учитываем знак*} If More(b,a)Then Begin c:=a; a:=b; b:=c; End; FillChar(c,SizeOf(c),0); C[0]:=1; For j:=1 To B[0] Do Begin For i:=1 To A[0] Do Begin C[i+j]:=C[i+j]+(Longint(A[i])*B[j]+C[i+j-1]) Div Osn; C[i+j-1]:=(Longint(A[i])*B[j]+C[i+j-1])Mod Osn; End; If C[A[0]+1]>0 Then C[0]:=A[0]+1 Else C[0]:=A[0]; End; C[C[0]+1]:=Sign; End;
Умножение на “короткое” число не превосходящее основание аналогично приведенной в [1], но с учетом знака.
Вариант процедуры деления без остатка:
Procedure Fission(A,B:TLong; Var DivLong:TLong); Var Sign,i,j,nac,con:Integer; C,D:TLong; Begin FillChar(DivLong,SizeOf(DivLong),0); {*Инициализация длинного частного*} Sign:=A[A[0]+1] Xor B[B[0]+1]; A[A[0]+1]:=0; B[B[0]+1]:=0; {*Учет знака*} FillChar(D,SizeOf(D),0); {*Инициализация дополнительного массива*} If More(A,B) Then {*Если A больше B, то записываем несколько старших разрядов в D и убираем их из A*} For j:=1 To B[0]-1 Do Begin Inc(D[0]); For i:=D[0] DownTo 2 Do D[i]:=D[i-1]; D[1]:=A[A[0]]; A[A[0]]:=0; Dec(A[0]); End; While A[0]>0 Do Begin{*Записываем очередной разряд в D*} Inc(D[0]); For i:=D[0] DownTo 2 Do D[i]:=D[i-1]; D[1]:=A[A[0]]; A[A[0]]:=0; Dec(A[0]); While More(B,D) Do Begin {*Если D меньше B, то увеличиваем D, и увеличиваем DivLong на пустой разряд*} Inc(DivLong[0]); For i:=DivLong[0] DownTo 2 Do DivLong[i]:=DivLong[i-1]; DivLong[1]:=0; Inc(D[0]); For i:=D[0] DownTo 2 Do D[i]:=D[i-1]; D[1]:=A[A[0]]; A[A[0]]:=0; Dec(A[0]); End;
{*Подбираем цифру при умножении на которую число B*i максимально «близко» к D, но не превышает его*} nac:=1; con:=Osn-1; While nac+1{*Изменяем D. D:=D-B*i *} Umn(B,nac,C); Minus(D,C,D); Dec(D[0]);
{*При приписываем i в DivLong*} Inc(DivLong[0]); For i:=DivLong[0] DownTo 2 Do DivLong[i]:=DivLong[i-1]; DivLong[1]:=nac; End; DivLong[DivLong[0]+1]:=Sign; End;

_____
Как заработать в сети, как получать доход на сайте - блог студента-копирайтера даст ответ на этот вопрос!