高精度乘法和除法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高精度乘法和除法相关的知识,希望对你有一定的参考价值。

求高精度乘法复杂度o(nlgn)的函数
和高精度除法函数
返回值为一个类吧,字符串数组类

参考技术A 大数乘法,加法,除法

#include <stdio.h>
#define MAXINT 1000
int compare(int a[],int b[]);
int bigplus(int a[],int b[],int c[]);
int bigsub(int a[],int b[],int c[]);
int bigmult(int a[],unsigned int b,int c[]);
int bigmult2(int a[],int b[],int c[]);
int bigdiv(int a[],unsigned int b,int c[],int *d);
int bigdiv2(int a[],int b[],int c[],int d[]);
int main(int argc, char *argv[])

int a[MAXINT]=10,5,4,6,5,4,3,2,1,1,1; //被乘数或被除数
int b[MAXINT]=7,7,6,5,4,3,2,1; //乘数或除数
int c[MAXINT],d[MAXINT]; //c[]存放商,d[]存放余数
int div=1234; //小乘数或小除数
int k=0;
int *res=&k; //小余数整数指针
bigplus(a,b,c);
bigsub(a,b,c);
bigmult(a,div,c);
bigmult2(a,b,c);
bigdiv(a,div,c,res);
bigdiv2(a,b,c,d);
getchar();
return 0;

int compare(int a[],int b[]) //比较大整数的大小

int i;
if (a[0]>b[0]) return 1; //比较a,b的位数确定返回值
else if (a[0]<b[0]) return -1;
else //位数相等时的比较

i=a[0];
while (a[i]==b[i]) //逐位比较
i--;
if (i==0) return 0;
else if (a[i]>b[i]) return 1;
else return -1;


int bigplus(int a[],int b[],int c[]) //大整数加法

int i,len;
len=(a[0]>b[0]?a[0]:b[0]); //a[0] b[0]保存数组长度,len为较长的一个
for(i=0;i<MAXINT;i++) //将数组清0
c[i]=0;
for (i=1;i<=len;i++) //计算每一位的值

c[i]+=(a[i]+b[i]);
if (c[i]>=10)

c[i]-=10; //大于10的取个位
c[i+1]++; //高位加1


if (c[i+1]>0) len++;
c[0]=len; //c[0]保存结果数组实际长度
printf("Big integers add: ";
for (i=len;i>=1;i--)
printf("%d",c[i]); //打印结果
printf("\n";
return 0;

int bigsub(int a[],int b[],int c[]) //大整数减法

int i,len;
len=(a[0]>b[0]?a[0]:b[0]); //a[0]保存数字长度,len为较长的一个
for(i=0;i<MAXINT;i++) //将数组清0
c[i]=0;
if (compare(a,b)==0) //比较a,b大小

printf("Result:0";
return 0;

else if (compare(a,b)>0)
for (i=1;i<=len;i++) //计算每一位的值

c[i]+=(a[i]-b[i]);
if (c[i]<0)

c[i]+=10; //小于0的原位加10
c[i+1]--; //高位减1


else
for (i=1;i<=len;i++) //计算每一位的值

c[i]+=(b[i]-a[i]);
if (c[i]<0)

c[i]+=10; //小于0原位加10
c[i+1]--; //高位减1


while (len>1 && c[len]==0) //去掉高位的0
len--;
c[0]=len;
printf("Big integers sub= ";
if (a[0]<b[0]) printf("-";
for(i=len;i>=1;i--) //打印结果
printf("%d",c[i]);
printf("\n";
return 0;

int bigmult(int a[],unsigned int b,int c[])//高精度乘以低精度

int len,i;
for (i=0;i<MAXINT;i++) //数组清0
c[i]=0;
len=a[0];
for(i=1;i<=len;i++) //对每一位计算

c[i]+=a[i]*b;
c[i+1]+=c[i]/10;
c[i]%=10;

while (c[++len]>=10) //处理高位

c[len+1]=c[len]/10;
c[len]%=10;

if (c[len]==0) len--; //处理高进位为0情况
printf("Big integrs multi small integer: ";
for (i=len;i>=1;i--)
printf("%d",c[i]);
printf("\n";

int bigmult2(int a[],int b[],int c[]) //高精度乘以高精度

int i,j,len;
for (i=0;i<MAXINT;i++) //数组清0
c[i]=0;
for (i=1;i<=a[0];i++) //被乘数循环
for (j=1;j<=b[0];j++) //乘数循环

c[i+j-1]+=a[i]*b[j]; //将每一位计算累加
c[i+j]+=c[i+j-1]/10; //将每一次结果累加到高一位
c[i+j-1]%=10; //计算每一次的个位

len=a[0]+b[0]; //取最大长度
while (len>1 && c[len]==0) //去掉高位0
len--;
c[0]=len;
printf("Big integers multi: ";
for (i=len;i>=1;i--) //打印结果
printf("%d",c[i]);
printf("\n";

int bigdiv(int a[],unsigned int b,int c[],int *d) //高精度除以低精度
//a[] 为被乘数,b为除数,c[]为结果,d为余数
int i,len;
len=a[0]; //len为a[0]的数组长度
for (i=len;i>=1;i--)

(*d)=10*(*d)+a[i]; //计算每一步余数
c[i]=(*d)/b; //计算每一步结果
(*d)=(*d)%b; //求模余数

while (len>1 && c[len]==0) len--; //去高位0
printf("Big integer div small integer: ";
for (i=len;i>=1;i--) //打印结果
printf("%d",c[i]);
printf("\tArithmetic compliment:%d",*d);
printf("\n";

int bigdiv2(int a[],int b[],int c[],int d[]) //高精度除以高精度

int i,j,len;
if (compare(a,b)<0) //被除数较小直接打印结果

printf("Result:0";
printf("Arithmetic compliment:";
for (i=a[0];i>=1;i--) printf("%d",a[i]);
printf("\n";
return -1;

for (i=0;i<MAXINT;i++) //商和余数清0

c[i]=0;
d[i]=0;

len=a[0];d[0]=0;
for (i=len;i>=1;i--) //逐位相除

for (j=d[0];j>=1;j--)
d[j+1]=d[j];
d[1]=a[i]; //高位*10+各位
d[0]++; //数组d长度增1
while (compare(d,b)>=0) //比较d,b大小

for (j=1;j<=d[0];j++) //做减法d-b

d[j]-=b[j];
if (d[j]<0)

d[j]+=10;
d[j+1]--;


while (j>0 && d[j]==0) //去掉高位0
j--;
d[0]=j;
c[i]++; //商所在位值加1


j=b[0];
while (c[j]==0 && j>0) j--; //求商数组c长度
c[0]=j;
printf("Big integers div result: ";
for (i=c[0];i>=1;i--) //打印商
printf("%d",c[i]);
printf("\tArithmetic compliment: "; //打印余数
for (i=d[0];i>=1;i--)
printf("%d",d[i]);
printf("\n";

高精度加法,减法,乘法,除法

主要分为5个方面来开展:

1.高精度数的存储,我是按照《晴神宝典》的用一个包含int数组和表示长度int的struct bign来存储数据,当然了,为了方便,我们存储方向和我们正常的数字大小排列方向相反,我们是数组低位存放阶数小的数字,这样方便之后的计算

2.加法,加法应该就是直接模拟,记得用一个carry来存放进位就行了,其他的没有什么好说

2.减法,减法的话就是多了个向高处借位,既高一位的地方-1,自己位置+10,最后要消除前导0

4.乘法,乘法也是简单模拟,两个数的每一位和每一位相乘,然后再相加

5.除法,除法是最难的一个,虽然也是模拟,但是你使用高精度数除以一个高精度数的时候还是有点难度,首先整个模拟过程要清晰:

  输入的被除数a,除数b

  每一个循环的被除数=余数*10+当前位置数,用被除数除以除数(除数即为我们输入的除数b),如果

  (1)够除的话,那就得到商,和新的余数

  (2)如果不够除,就直接把被除数赋给余数

  进入下一个循环,直至a的位数都用完

  这里有一个技巧就是(1)中要怎么除,因为是高精度除以高精度,所以没办法使用内置除法,故此处使用减法来模拟除法(即不断地去减,直至减不了)

 

#include<iostream>
#include<stdio.h>
#include<string>
#include<cstring>
using namespace std;

const int max_size=1000;

struct bign
    int d[max_size];
    int len;
    bign()
        len=0;
        memset(d,0,sizeof(d));
     
;

bign to_bign(string str)
    bign big;
    int size=str.size();
    big.len=size;
    for(int i=0;i!=size;++i)
        big.d[i]=str[size-1-i]-0;  //注意这里是string的char转化为int,要用-‘0‘变通一下 
    return big;


bign add(bign a,bign b)
    bign c;
    int carry=0;
    for(int i=0;i<=a.len-1 || i<=b.len-1;++i)
        int temp=carry+a.d[i]+b.d[i];
        c.d[c.len++]=temp%10;
        carry=temp/10;
     
    if(carry!=0)
        c.d[c.len++]=carry;
    
    return c;


int cmp(bign a,bign b)
    int i;
    if(a.len>=b.len)
        i=a.len;
    else i=b.len;
    for(;i>=0;i--)
        if(a.d[i]>b.d[i]) return 1;
        else if(a.d[i]<b.d[i]) return -1;
    
    return 0;


bign sub(bign a,bign b) //a-b, 保证a>b 
    bign c;
    for(int i=0;i<a.len;++i)  //a肯定是长的那一个 
        if(a.d[i]-b.d[i]<0)
            a.d[i+1]--;
            a.d[i]+=10;
        
        c.d[c.len++]=a.d[i]-b.d[i];
    
    //消除前导0
    while(c.len-1>=1 && c.d[c.len-1]==0)
        c.len--;
    
    return c;


bign multi(bign a,bign b)
    bign c;
    for(int i=0;i<a.len;++i)
        int m=a.d[i];
        for(int j=0;j<b.len;++j)
            int temp=c.d[i+j]+m*b.d[j];
            c.d[i+j]=temp%10;
            c.d[i+j+1]+=temp/10;
        
    
    if(c.d[a.len+b.len-1]!=0)
        c.len=a.len+b.len;
    else c.len=a.len+b.len-1;
    return c;
 

//高精度除以高精度,好难写啊,原来我是卡在用减法模拟除法那里了 
bign result_n;
bign remain_n;
bign division(bign a,bign b) //a/b
    int bits=b.len;
    bign remain;
    bign sub1; 
    string result_str;
    for(int i=a.len-1;i>=0;--i)
        remain=multi(remain,to_bign("10")); //余数*10
        string str;
        str+=(0+a.d[i]);
        sub1=add(remain,to_bign(str));
        int if_bigger=cmp(sub1,b);
        if(if_bigger>=0)
            //法模拟除法
            int count=0;
            while(cmp(sub1,b)>=0)
                sub1=sub(sub1,b);
                count++;
            
            result_str+=(0+count); //存下商 
            remain=sub1; //保留此次余数 
        
        else
            remain=sub1;
        
    
    result_n=to_bign(result_str);
    remain_n=remain;


void print_bign(bign b)
    for(int i=b.len-1;i>=0;--i)
        printf("%d",b.d[i]);


int main()
    freopen("in.txt","r",stdin);
    
    string str1,str2;
    cin>>str1>>str2;  //string对象的读写还是用cin>>string和cout<<string,不要用scanf,printf,不然有问题 
    bign b1=to_bign(str1);
    bign b2=to_bign(str2);

    division(b1,b2);
    print_bign(result_n);
    printf("   ");
    print_bign(remain_n);
    
    return 0;

 

以上是关于高精度乘法和除法的主要内容,如果未能解决你的问题,请参考以下文章

高精度 加法 减法 乘法 除法 整合

java里面double 做乘法和加法会丢失精度嘛?

高精除~~~

『数论』乘法逆元

高精度乘除法模板(AcWing.793 794)

乘法逆元模板