Реализация
Сайт: | Информатикс |
Курс: | Арифметика и числовые алгоритмы |
Книга: | Реализация |
Напечатано:: | Гость |
Дата: | Воскресенье, 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;
}