Загрузка данных
//длинная арифметика Окулов Ф.М.+ отрицательные
#include <string.h>
#include <stdio.h>
#include <math.h>
#define MaxDig 1000 //Максимальное количество цифр — четырехзначных!
#define Osn 0x100 //Основание нашей системы счисления, в элементах массива храним двузначные шестнадцатиричные числа
#define mm 8 //число двоичных разрядов у Osn
//структура данных, количество "цифр" в массиве, сами цифры, они определяются системой счисления, знак числа
typedef struct{
int lm[MaxDig]; //массив чисел
int len; //размер массива, кол-во чисел
int sign; //знак числа (-1,+1);
} LDig;
//перевод строки в длинное число
void Read16Long1(LDig *A, char *S){
char ch;
int i,j, len;
len= strlen(S); //??????
for (i=0;i<len;i++){
//считываем символ
ch=S[i];
//еслм отрицательное, то устанавливаем sign
if (ch=='-'){
A->sign=-1;
i++;
ch=S[i];
}
switch (ch){
case 'a': ch=0xa;
break;
case 'A': ch=0xa;
break;
case 'b': ch=0xb;
break;
case 'B': ch=0xb;
break;
case 'c': ch=0xc;
break;
case 'C': ch=0xc;
break;
case 'd': ch=0xd;
break;
case 'D': ch=0xd;
break;
case 'e': ch=0xe;
break;
case 'E': ch=0xe;
break;
case 'f': ch=0xf;
break;
case 'F': ch=0xf;
break;
default: ch=ch-0x30;
break;
}
//вставляем в массив
for (j=A->len;j>=0;j--){
//"протаскивание" старшей цифры в числе из A[j]
//в младшую цифру числа из A[j+l]
A->lm[j+1] = A->lm[j+1] + (A->lm[j]*16)/Osn; //одна буква - 4 бита = 16, перетаскиваем на одну позицию
A->lm[j] = (A->lm[j]*16)%Osn;
}
A->lm[0] = A->lm[0] + ch;//добавляем младшую цифру к числу из А[1]}
//изменяем длину, число задействованных элементов массива А}
if (A->lm[A->len] > 0) A->len++;
if (A->lm[A->len+1] > 0) A->len++;
}
return;
}
void Read16Long(LDig *A, char *S){
char chs[3], s[256];
int i,len, b[100],ch,k=0 ;
if (S[0]=='-'){
A->sign = -1;
k=1;}
//для положительных
strcpy(chs,"");
len= strlen(S);
A->len = len/2;
for (i=k;i<len;i+=2){
chs[0]=S[i];
chs[1]=S[i+1];
chs[2]='\0';
sscanf(chs,"%02x",&ch);
b[i/2]=ch;
}
for(i=0; i<A->len;i++)
A->lm[A->len-1-i]=b[i];
}
//перевод короткого (целого - 2 байта) числа в строку
void Dig16Str(int k, char *s){
int num=0, d, os,i;
char s1[256];
d=k;
//формируем строку
do{
os=d%16;
switch (os){
case 10: s1[num]= 'a';
break;
case 11: s1[num]= 'b';
break;
case 12: s1[num]= 'c';
break;
case 13: s1[num]= 'd';
break;
case 14: s1[num]= 'e';
break;
case 15: s1[num]= 'f';
break;
default: s1[num]=os+0x30;
break;
}
d=d/16;
num++;
} while (d!=0);
//если отрицательное
if (k<0) {s1[num]='-'; num++;}
//запись числа задом наперед
s[num]= '\0';
for (i=num-1;i>=0;i--) s[num-1-i]=s1[i];
return;
}
//запись длинного числа в строку
void Write16Long(LDig *A, char *S){
char ls[256];
char s[10];
int i,j,k=0,n,len1;
//если отрицательное
if (A->sign<0) strcpy(S,"-");
else strcpy(S,"");
strcpy(s,"");
//рабочая строка
for (i=A->len-1;i>=0;i--){
sprintf(s,"%02x", A->lm[i]);
strcat(S,s);
}
return;
}
void Write16Long1(LDig *A, char *S){
char ls[256];
char s[256];
int i,j,k=0,n,len1;
//если отрицательное
if (A->sign<0) {S[k]='-';k++;}
//строка для основания системы счисления
Dig16Str(Osn/16,ls);
//рабочая строка
for (i=A->len-1;i>=0;i--){
Dig16Str(A->lm[i],s);
//заполняем нулями перед цифрами, если надо
while((strlen(s)<strlen(ls))&&(i!=A->len-1)){
len1=strlen(s);
//сдвигаем число
for (n=len1;n>0;n--) s[n]=s[n-1];
s[0]= '0' ; s[1]= '0';
s[len1+1]= '\0' ;
}
//вставляем в основную строку
for (j=0;j<strlen(s);j++) S[k+j]=s[j];
k=k+j;
}
S[k]='\0';
return;
}
//распечатка длинного числа
void ShowLong(LDig *A){
int i;
for (i=0; i<A->len;i++) printf("%d ",A->lm[i]);
printf("\n");
return;
}
//распечатка длинного числа в строку
void ShowLongS(LDig *A){
char S[256];
Write16Long(A, S);
printf("%s\n",S);
return;
}
//инициализация LDig
void InitLong(LDig *A){
int i;
for (i=0; i<MaxDig; i++) A->lm[i]=0;
A->len=1; A->sign=1; //положительное, нулевой вектор
return;
}
//перевод целого числа в массив
void DigToArray(int k, LDig *A){
int res, i=0, sign=1;
if (k<0) sign=-1;
res=fabs(k);
while (res>0){
A->lm[i]=res%Osn;
res/=Osn;
i++;
}
A->len=i;
A->sign=A->sign*sign;
return;
}
//Сравнение двух длинных чисел: равно (1), не равно (0)
int Eq(LDig *A, LDig *B){
int i;
if ((A->len!=B->len)||(A->sign!=B->sign)) return 0; //разные длины, знаки , нельзя сравнивать не равны
else {
i=0;
//сравниваем поразрядно
while ((i<A->len)&&(A->lm[i]==B->lm[i])) i++;
}
return i==A->len;
}
//Сравнение положительных |A|>|B| больше (1), |A|<|B| меньше (0)
int More(LDig *A, LDig *B) {
int i, sr=0;
if (A->len<B->len) sr=0; //меньше
else
if(A->len>B->len) sr=1; //больше
else{
i=A->len-1;
while ((i>0)&&(A->lm[i]==B->lm[i])) i--;
if (i==-1) sr=0;
else
if (A->lm[i]>B->lm[i]) sr=1;
else sr=0;
}
return sr;
}
//положительные
//сравнение со сдвигом, сдвигаем B
//результат 0, если |A|>|B|; 1, если |A|<|B|; 2, если |A|=|B|
int More_Shift(LDig *A, LDig *B, int sp){
int res,i;
if (A->len>B->len+sp) res=0;
else{
if (A->len<B->len+sp) res=1;
else{
i=A->len-1;
while ((i>sp-1)&&(A->lm[i]==B->lm[i-sp])) i--;
if (i==sp-1) {
res=0;
//совпадение чисел с учетом сдвига
for(i=0;i<sp-1;i++) if (A->lm[i]>0) return res;
res=2; //числа равны, "хвост" числа А равен нулю
}
else res=(A->lm[i]<B->lm[i-sp]);
}
}
return res;
}
//|A|<|B|
int Less(LDig*A, LDig *B){
return !(More(A,B)||Eq(A,B));
}
//|A|>=|B|
int More_Eq(LDig *A, LDig *B){
return More(A,B)||Eq(A,B);
}
//|A|<=|B|
int Less_Eq(LDig *A,LDig *B){
return !More(A,B);
}
//проверка на равенство нулю A=0 (1, иначе 0)
int IsNulLong(LDig *A){
if ((A->len==1)&&(A->lm[0]==0)) return 1;
else return 0;
}
//Умножение длинного числа на короткое (Osn), результат в C
void Mul(LDig *A, int K, LDig*C){
int i;
InitLong(C);
if (K!=0){
for (i=0;i<A->len;i++){
C->lm[i+1]=(C->lm[i]+A->lm[i]*fabs(K))/Osn;
C->lm[i]=(C->lm[i]+A->lm[i]*(int)fabs(K))%Osn;
}
//определяем длину результата
if (C->lm[A->len]>0) C->len=A->len+1;
else C->len=A->len;
}
C->sign=A->sign*(K/fabs(K));
return;
}
//Умножение длинного числа на короткое (<Osn), результат в A
void MulA(LDig *A, int K){
LDig C;
InitLong(&C);
Mul(A, K, &C);
*A=C;
return;
}
//положительные
//вычитание двух длинных чисел с учетом сдвига |A|>|B|, результат в A (вычитание модулей, без учета знака)
//sp- число разрядов для сдвига, сдвигаем B
void Sub_Shift(LDig *A, LDig *B, int sp){
int i,j;
//из А вычитаем В с учетом сдвига sp, результат вычитания в А
for (i=0; i<B->len;i++){
A->lm[i+sp]-=B->lm[i];
j=i;
//реализация сложного заимствования
while ((A->lm[j+sp]<0)&&(j<A->len-1)){
A->lm[j+sp]+=Osn;
A->lm[j+sp+1]--;
j++;
}
}
//корректировка длины результата операции
i = A->len-1;
while( (i > 0)&&(A->lm[i] == 0)) i--;
A->len = i+1;
return;
}
//положительные
//Сложение двух длинных чисел |A| и |B| с учетом сдвига, результат в A (сложение модулей без учета знака)
//sp- число разрядов для сдвига, сдвигаем B !!!нет у Окулова
void Sum_Shift(LDig *A, LDig*B, int sp){
int i,k;
if (A->len>B->len+sp) k=A->len;
else k=B->len+sp;
for (i=0;i<k;i++){
A->lm[i+sp+1]+=(A->lm[i+sp]+B->lm[i])/Osn;
A->lm[i+sp]=(A->lm[i+sp]+B->lm[i])%Osn;
}
if (A->lm[k]==0) A->len=k;
else A->len=k+1;
return;
}
//положительные
//сложение двух положительных чисел (столбиком), результат в C без учета знака
void SumTwo(LDig *A, LDig *B, LDig *C){
*C=*A;
Sum_Shift(C,B,0);
return;
}
//положительные
//вычитание |A|>|B|, результат в C
void SubTwo(LDig *A, LDig *B, LDig *C){
//из А вычитаем В с учетом сдвига sp, результат вычитания в А
*C=*A;
Sub_Shift(C,B,0);
return;
}
//сложение двух длинных со знаком, результат в C
void SumLong(LDig *A, LDig *B, LDig *C){
//Если оба одного знака - сумма
if (A->sign==B->sign){
SumTwo(A, B, C);
C->sign=A->sign;
}
//Знаки разные - разность
else{
if (A->len>B->len){
SubTwo(A, B, C);
C->sign=A->sign;
}
else{
SubTwo(B, A, C);
C->sign=B->sign;
}
}
return;
}
//сложение двух длинных со знаком, результат в A
void SumLongA(LDig *A, LDig *B){
LDig C;
InitLong(&C);
SumLong(A, B, &C);
*A=C;
return;
}
//вычитание двух длинных со знаком, результат в C
void SubLong(LDig *A, LDig *B, LDig *C){
//знаки разные - сумма
if (A->sign!=B->sign){
SumTwo(A, B, C);
C->sign=A->sign;
}
//знаки одинаковые
else{
if (More(A, B)){
SubTwo(A,B,C);
C->sign=A->sign;
}
else{
SubTwo(B, A, C);
C->sign=-B->sign;
}
}
return;
}
//вычитание двух длинных со знаком, результат в A
void SubLongA(LDig *A, LDig *B){
LDig C;
InitLong(&C);
SubLong(A, B, &C);
*A=C;
return;
}
//Умножение двух длинных чисел со знаком !!!нет у Окулова, результат в C
void MulTwoLong(LDig *A, LDig *B, LDig*C){
int i;
LDig C1;
InitLong(&C1);
for (i=0;i<B->len;i++){
Mul(A, B->lm[i], &C1);
Sum_Shift(C, &C1 , i);
}
C->sign=A->sign*B->sign;
return;
}
//Умножение двух длинных чисел со знаком !!!нет у Окулова, результат в A
void MulTwoLongA(LDig *A, LDig *B){
LDig C;
InitLong(&C);
MulTwoLong(A, B, &C);
*A=C;
return;
}
/*
//Сложение модальное, результат в A (аргументы - остатки по модулю)
void SumLongmA(LDig *A, LDig *B, LDig p){
LDig C;
InitLong(&C);
//Если оба одного знака - сумма
if (A->sign==B->sign) Sum_Shift(A, B, 0);
//Знаки разные - разность
else{
if (A->len>B->len) Sub_Shift(A, B,0);
else{
C=*B;
Sub_Shift(&C, A, 0);
*A=C;
A->sign=B->sign;
}
}
if???
return;
}*/
//деление двух длинных чисел (частное и остаток)
//=================================================
//двоичный поиск - подбираем результат деления
int FindBin(LDig *Ost, LDig *B, int sp){
int Down=0, Up=Osn,k;
LDig C;
InitLong(&C);
while(Up-1>Down){
Mul(B, (Up + Down)/2, &C);
k=More_Shift(Ost, &C, sp);
switch (k) {
case 0: Down = (Down + Up)/2;
break;
case 1: Up = (Up + Down)/2;
break;
case 2: Up = (Up + Down)/2;
Down = Up;
break;
}
}
Mul(B, (Up + Down)/2, &C);
//находим остаток от деления
if (More_Shift (Ost, &C, 0) == 0) Sub_Shift(Ost, &C, sp);
else {
Sub_Shift (&C, Ost, sp);
*Ost = C;
}
return (Up + Down)/2; //целая часть частного
}
void MakeDel(LDig *A, LDig *B, LDig *Res, LDig *Ost){
int sp;
//первоначальное значение остатка Ost=A
*Ost = *A;
sp=A->len-B->len;
if (More_Shift(A,B,sp)==1) sp--;
//B * Osn > A, в результате одна цифра
Res->len=sp+1;
while (sp>=0){
//находим очередную цифру результата
Res->lm[sp]=FindBin(Ost,B,sp);
sp--;
}
return;
}
//остаток может быть отрицательным
void LongDivLong(LDig *A, LDig *B, LDig *Res, LDig *Ost){
switch (More_Shift(A,B,0)){
case 0: MakeDel(A,B,Res,Ost);
break;
case 1: *Ost=*A; //А меньше В
break;
case 2: Res->lm[1]=1; //А равно В
break;
}
Res->sign=A->sign*B->sign;
Ost->sign=A->sign*B->sign;
//если остаток - отрицательный
/* if ((Ost->sign<0)&&!IsNulLong(Ost)){
SumLongA(Ost, B);
}*/
return;
}
/*
int main(){
LDig A;
int i;
char S[]="34FF";
InitLong(&A);
Read16Long1(&A, S);
ShowLongS(&A);
for (i=A.len-1;i>=0;i--)
printf("%x", A.lm[i]);
printf("\n");
return 0;
}*/