Реализация

Сайт: Информатикс
Курс: Арифметика и числовые алгоритмы
Книга: Реализация
Напечатано:: Гость
Дата: Воскресенье, 31 Август 2025, 21:57

Оглавление


//(C) Igor Kvasov
const
  maxl = 100;

type
  Long = record
    l:longint;
    d:array[1..maxl] of longint;{must be signed type,        }
  end;                          {important fo sub proc.      }

procedure short2long(a:longint;var b:long);
begin
  b.l:=0;
  while a>0 do begin
    inc(b.l);
    b.d[b.l]:=a mod 10;
    a:=a div 10;
  end;
  if a=0 then begin b.l:=1; b.d[1]:=0; end;
end;

procedure readlong(var a:long);
var
  ch:char;
  i,buf:longint;

begin
  a.l:=0;
  while not eoln do begin
    read(ch); inc(a.l); a.d[a.l]:=ord(ch)-ord('0');
  end;
  if not eof then readln;
  if a.l=0 then begin a.l:=1; a.d[1]:=0; end;
  for i:=1 to a.l div 2 do begin
    buf:=a.d[i]; a.d[i]:=a.d[a.l-i+1]; a.d[a.l-i+1]:=buf;
  end;
end;

procedure outlong(a:long);
var
  i:longint;

begin
  for i:=a.l downto 1 do write(a.d[i]);writeln;
end;

function cmp(a,b:long):longint;
var
  i:longint;

begin
  if a.l<b.l then begin cmp:=-1;exit;end else
  if a.l>b.l then begin cmp:=1;exit;end else
  for i:=a.l downto 1 do
  if a.d[i]<b.d[i] then begin cmp:=-1;exit;end else
  if a.d[i]>b.d[i] then begin cmp:=1;exit;end;
  cmp:=0;
end;

procedure sum(a,b:long;var c:long);
var
  i,um:longint;

begin
  if a.l<b.l then begin for i:=a.l+1 to b.l do a.d[i]:=0; a.l:=b.l;end;
  if a.l>b.l then begin for i:=b.l+1 to a.l do b.d[i]:=0; b.l:=a.l;end;
  um:=0;
  for i:=1 to a.l do begin
    c.d[i]:=(a.d[i]+b.d[i]+um)mod 10;
    um:=(a.d[i]+b.d[i]+um)div 10;
  end;
  if um=0 then c.l:=a.l else begin c.l:=a.l+1; c.d[c.l]:=1;end;
end;

procedure sub(a,b:long;var c:long); {expected a>=b}
var
  i,um:longint;

begin
  for i:=b.l+1 to a.l do b.d[i]:=0;
  um:=0;
  for i:=1 to a.l do begin
    c.d[i]:=a.d[i]-b.d[i]-um;
    um:=ord(c.d[i]<0);
    if um=1 then c.d[i]:=c.d[i]+10;
  end;
  c.l:=a.l;
  while (c.l>1)and(c.d[c.l]=0) do dec(c.l);
end;

procedure mul(a,b:long;var c:long);
var
  i,j,um,s:longint;

begin
  c.l:=a.l+b.l;
  for i:=1 to c.l do c.d[i]:=0;
  for i:=1 to a.l do
    for j:=1 to b.l do c.d[i+j-1]:=c.d[i+j-1]+a.d[i]*b.d[j];
  um:=0;
  for i:=1 to c.l do begin
    s:=(c.d[i]+um)mod 10;
    um:=(c.d[i]+um)div 10;
    c.d[i]:=s;
  end;
  while (c.l>1)and(c.d[c.l]=0) do dec(c.l);
end;

procedure mulShort(a:long;b:longint;var c:long);
var
  i,um:longint;

begin
  for i:=a.l+1 to a.l+10 do a.d[i]:=0;
  um:=0;
  for i:=1 to a.l+10 do begin
    c.d[i]:=(a.d[i]*b+um)mod 10;
    um:=(a.d[i]*b+um)div 10;
  end;
  c.l:=a.l+10;
  while (c.l>1)and(c.d[c.l]=0) do dec(c.l);
end;

procedure del(a,b:long;var c,d:long);
var
  i,j,l,r,m:longint;
  e:long;

begin
  d.l:=0;
  for i:=a.l downto 1 do begin
    if (d.l=1)and(d.d[1]=0)then d.l:=0;
    for j:=d.l downto 1 do d.d[j+1]:=d.d[j];
    d.d[1]:=a.d[i]; inc(d.l);
    l:=0; r:=9;
    while l<r do begin
      m:=(l+r+1)div 2;
      mulShort(b,m,e);
      if cmp(e,d)=1 then r:=m-1 else l:=m;
    end;
    if l<>m then mulShort(b,l,e);
    c.d[i]:=l; sub(d,e,d);
  end;
  c.l:=a.l;
  while (c.l>1)and(c.d[c.l]=0) do dec(c.l);
end;

procedure delShort(a:long;b:longint;var c:long;var d:longint);
var
  i:longint;

begin
  d:=0;
  for i:=a.l downto 1 do begin
    d:=d*10+a.d[i];
    c.d[i]:=d div b;
    d:=d mod b;
  end;
  c.l:=a.l;
  while (c.l>1)and(c.d[c.l]=0) do dec(c.l);
end;

begin
end.

Anton Malykh - 18 Mar 2004


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream.h>


// Количество цифр после запятой
#define NEG_ACC 30
// Количество цифр до запятой
#define POS_ACC 30
// Макрос, выцепляющий i-ю цифру (положительные i -
// цифры после запятой, отрицательные - до)
#define DIGIT(longnum, i) ( (longnum).data[(i)+NEG_ACC] )
// Собственно тип длинного числа
struct LongNum{
   LongNum(){
      // при инициализации записываем ноль
      flush();
   }
   void flush(){
      // функция обнуления числа
      int i;
      for(i=0;i<NEG_ACC+POS_ACC;i++)
         data[i]=0;
      sign = 1;
   }

   // функция, выцепляющая i-ю цифру
   char inline digit(int i) const {return data[i+NEG_ACC];}
   // массив, в котором хранятся цифры
   char data[NEG_ACC+POS_ACC];
   // знак: +1 или -1
   signed char sign;
};

// вводит с клавиатуры длинное число
struct LongNum LNinput()
{
   char s[NEG_ACC+POS_ACC+10];
   int i,j,k;
   struct LongNum res;
   cin >> s;

   if(s[0]=='-'){
      res.sign = -1;
      i=1;
   }else{
      res.sign = 1;
      i=0;
   }

   j = POS_ACC-1;
   for(;i<strlen(s) && s[i]!='.';i++){
      DIGIT(res, j--) = s[i]-'0';      
   }
   j++;
   for(k=j;k<POS_ACC;k++)
      DIGIT(res, k-j) = DIGIT(res,k);
   for(k=POS_ACC;k-j<POS_ACC;k++)
      DIGIT(res, k-j) = 0;
   if(s[i]=='.'){
      j=-1;
      for(i++;i<strlen(s);i++)
         DIGIT(res, j--) = s[i]-'0';
   }
   return res;
}

// выводит на экран длинную чиселку
void LNoutput(struct LongNum ln)
{
   if(ln.sign == -1)cout << '-';
   
   // переменная flag определяет встретили ли мы какую-либо
   // значащую цифру при движении от старших разрядов к младшим

   int i, j, flag=0;
   for(i=POS_ACC-1;i>=0;i--)
      if( flag || ln.digit(i)!=0 ){
         flag = 1;
         cout << (char)(ln.digit(i)+'0');
      }
   if(!flag)cout << '0';
   j = 0;
   for(i=-NEG_ACC;i<0;i++)
      if(ln.digit(i)!=0){
         j = i;
         break;
      }
   if(j != 0){
      cout << '.';
      for(i=-1; i>=j; i--)
         cout << (char)(ln.digit(i)+'0');
   }
}

// переводит короткое число в длинное
struct LongNum toLN(int n)
{
   struct LongNum res;
   if(n<0){
      res.sign = -1;
      n = -n;
   } else res.sign = 1;
   int i=0,p10=1;
   while((p10*10)/10==p10){
      p10*=10;
      i++;
   }
   for(;i>=0;i--){
      DIGIT(res, i) = n/p10;
      n %= p10;
      p10 /= 10;
   }
   return res;
}

// сравнение ПО МОДУЛЮ двух длинных чисел
// возвращает 1 если |a|>|b|; -1 если |a|<|b|
// и возвращает 0 если они равны
int LNabscmp(const struct LongNum &a, const struct LongNum &b)
{
   int i;
   for(i=POS_ACC-1; i>=-NEG_ACC; i--){
      if(a.digit(i)==b.digit(i))continue;
      if(a.digit(i)>b.digit(i))return 1;
      if(a.digit(i)<b.digit(i))return -1;
   }
   return 0;
}

// сравнение двух длинных чисел
// возвращает 1 если a>b ; -1 если a<b
// и возвращает 0 если они равны
int LNcmp(const struct LongNum &a, const struct LongNum &b)
{
   if(a.sign == 1 && b.sign == -1)return 1;
   if(a.sign == -1 && b.sign == 1)return -1;
   if(a.sign == 1 && b.sign == 1)return LNabscmp(a,b);
   if(a.sign == -1 && b.sign == -1)return -LNabscmp(a,b);
   return 0;//never executed
}

// возвращает ln-subtractment
// описана ниже
void LNsubLN(struct LongNum &ln, struct LongNum subtractment);

// возвращает ln+addment
// результат сохраняется в ln
void LNaddLN(struct LongNum &ln, struct LongNum addment)
{
   int i,p;
   if(ln.sign == addment.sign){
       p=0;
      for(i=-NEG_ACC;i<POS_ACC;i++){
         p += ln.digit(i) + addment.digit(i);
         DIGIT(ln, i) = p%10;
         p/=10;
      }
   }else{
      if(ln.sign == -1){
         struct LongNum dummy = ln;
         ln = addment;
         addment = dummy;
      }
      int cmp = LNabscmp(ln,addment);
      if(cmp == 0)
         ln.flush();
      else if(cmp > 0){
         addment.sign = 1;
         LNsubLN(ln, addment);
      }else{ // cmp < 0
         addment.sign = 1;
         LNsubLN(addment, ln);
         ln = addment;
         ln.sign = -1;
      }
   }
}

// возвращает ln-subtractment
// результат сохраняется в ln
void LNsubLN(struct LongNum &ln, struct LongNum subtractment)
{
    if(subtractment.sign == -1){
      subtractment.sign = 1;
      LNaddLN(ln, subtractment);
      return;
   }

   if(ln.sign == -1){
      ln.sign = 1;
      LNaddLN(ln, subtractment);
      ln.sign = -ln.sign;
      return;
   }

   int cmp = LNabscmp(ln, subtractment);
   if(cmp == 0){
      ln.flush();
      return;
   }

   if(cmp < 0){
      struct LongNum dummy = ln;
      ln = subtractment;
      subtractment = dummy;
      LNsubLN(ln, subtractment);
      ln.sign = -ln.sign;
      return;
   }

   int i, p=0;
   for(i=-NEG_ACC; i<POS_ACC; i++){
      p = ln.digit(i)-subtractment.digit(i)-p;
      DIGIT(ln, i) = (p+10)%10;
      if(p<0)p=1;else p=0;
   }
}

// умножает ln на multiplier
// результат сохраняется в ln
void LNmulLN(struct LongNum &ln, struct LongNum multiplier)
{
   ln.sign *= multiplier.sign;
   int i, j, k, p;
   struct LongNum res;

   for(i=-NEG_ACC; i<POS_ACC; i++){
      j=-NEG_ACC-i-1;
      if(j<-NEG_ACC)j=-NEG_ACC;
      for(; i+j<POS_ACC && j<POS_ACC; j++){
         p = ln.digit(i) * multiplier.digit(j);
         k = i+j;
         while(p>0 && k<POS_ACC){
            if(k>= -NEG_ACC && k<POS_ACC)
               DIGIT(res, k) += p%10;
            p /= 10;
            if(DIGIT(res,k) >= 10){
               p += DIGIT(res,k)/10;
               DIGIT(res,k) %= 10;
            }
            k++;
         }
      }
   }
   res.sign = ln.sign;
   ln = res;
}

// сдвигает ln на displacement десятичных разрядов влево
// может сдвигать вправо, если displacement<0
void LNshlLN(struct LongNum &ln, int displacement)
{
   int i;
   struct LongNum res;
   for(i=-NEG_ACC; i<POS_ACC; i++)
      if(
         i-displacement >= -NEG_ACC &&
         i-displacement < POS_ACC
      )
         DIGIT(res, i) = ln.digit(i-displacement);
   ln = res;
}

// возвращает в ln значение ln/dividor
void LNdivLN(
   struct LongNum &ln, struct LongNum divider)
{
   struct LongNum res, zero;
   res.flush(); zero.flush();
   int res_sign = ln.sign * divider.sign;
   ln.sign = divider.sign = 1;
   int p_ln, p_divider;
   if(LNcmp(ln, zero) == 0) return;
   if(LNcmp(divider, zero) == 0){
      ln.flush();
      return;
   }
   int i, j;
   for(i=POS_ACC-1;i>=-NEG_ACC;i--)
      if(ln.digit(i) != 0){
         p_ln = i;
         break;
      }
   for(i=POS_ACC-1;i>=-NEG_ACC;i--)
      if(divider.digit(i) != 0){
         p_divider = i;
         break;
      }
   i = p_ln-p_divider;
   if(i>POS_ACC) i = POS_ACC-1-p_divider;
   LNshlLN(divider, i);
   struct LongNum tempnum;
   for(;i>-NEG_ACC;i--){
      tempnum.flush();
      j=0;
      do{
         LNaddLN(tempnum, divider);
         j++;
      }while(LNabscmp(tempnum, ln) <= 0);
      LNsubLN(tempnum, divider);
      j--;
      LNsubLN(ln, tempnum);
      DIGIT(res, i) = j      
      LNshlLN(divider, -1);
   }
   res.sign = res_sign;
   ln = res;
}

 

// небольшая программа, демонстрирующая правильность работы
int main()
{
   struct LongNum ln1, ln2, lnsum, lndif, lnmul, lndiv;
   ln1 = toLN(11);
   ln2 = toLN(1);
   LNdivLN(ln1, toLN(10));
   LNdivLN(ln2, toLN(10));
   LNoutput(ln1);
   cout << endl;
   //int n;
   //cin >> n;
   //ln2 = toLN(n);
   LNoutput(ln2);
   cout << endl;
   lnsum = ln1;
   LNaddLN(lnsum, ln2);
   lndif = ln1;
   LNsubLN(lndif, ln2);
   cout << "a+b=";
   LNoutput(lnsum);
   cout << " a-b=";
   LNoutput(lndif);
   cout << endl << "a*b=";
   lnmul = ln1;
   LNmulLN(lnmul, ln2);
   LNoutput(lnmul);
   cout << endl << "a/b=";
   lndiv = ln1;
   LNdivLN(lndiv, ln2);
   LNoutput(lndiv);
   cout << endl;
   return 0;
}