目录

高精度算法

总起代码

加法高精度

减法高精度

乘法高精度

除法高精度


高精度算法

当我们利用计算机进行数值计算,有时候会遇到这样的问题: n!的精确结果是多少?
      当n小于30的时候,我们当然可以通过电脑自带的计算器计算出来。但是当我们遇到 100! 的时候就没有办法直接计算出精确的结果。再比如,求两个20000位的数的和。所谓高精度运算,是指参与运算的数(加数,减数,因子……)范围大大超过了标准数据类型(整型,实型)能表示的范围的运算。

高精度处理,实际上就是模拟法,模拟手算,它的原理与我们用竖式计算时一样的,不过在处理过程中要注意高精度数据的读入、转换储存、数据的计算、结果位数的计算、输出等几个问题。高精度计算中需要处理如下几个问题:

数据的输入

数据的输入,需要考虑输入的位数问题(可能成百上千位),也要考虑输入的数可能带字母(可能是16进制)等问题。所以我们可以采用字符串输入或者字符数组输入。

//方式一:
string s1,s2;
cin>>s1>>s2;
//方式二,使用字符数组的时候要注意,字符数组要分配足够的空间
char s1[200];
char s2[200];
cin>>s1>>s2;

数据的转换储存

数据是通过字符串输入的,不能够直接进行计算,需要转换成数字。我们选用最基本的转换储存方式,字符串的一个字符对应数组中的一个元素,把字符串的数字全部转换到一个数组中,其中数组下标为1对应输入数的个位,数组下标为2的对应输入数的十位,以此类推。

//使用字符串类型接收
string s1,s2;
int a[1000],b[1000];
void transfer(){int len1=s1.length();a[0]=len1;//将输入数据的位数存储在整型数组的第一个元素for(int i=0;i<len1;i++){a[i+1]=s1[len1-1-i]-'0';//逆序存储}int len2=s2.length();b[0]=len2;for(int i=0;i<len2;i++){b[i+1]=s2[len2-1-i]-'0';//逆序存储}
}
//使用字符数组接收
char s1[1010],s2[1010];
int a[1000],b[1000];
void transfer(){int len1=strlen(s1);a[0]=len1;//将输入数据的位数存储在整型数组的第一个元素for(int i=0;i<len1;i++){a[i+1]=s1[len1-1-i]-'0';//逆序存储}int len2=strlen(s2);b[0]=len2;for(int i=0;i<len2;i++){b[i+1]=s2[len2-1-i]-'0';//逆序存储}
}

通过这样,我们就可以把输入的数据很好的放入数组当中了。

数据的计算

参考相应的高精度运算专题版(包括加法、减法、乘法和除法)

结果位数的计算

去除最高位的0,在各个算法中都有体现

结果的输出

输出计算结果。

每种高精度运算的过程,大家可以通过一个竖式来提高自己的认识。对于除法的高精度可以了解一下,其他几个高精度的算法,必须掌握。

总起代码

#include <iostream>
#include <string>
using namespace std;const int N = 1e3;
string str1,str2;//输入操作数int num1[N],num2[N];//转化后的操作数
int num3[N];
void transfer(string s, int n[]);
void print(int n[]);void add(int n1[],int n2[],int n3[]);
void sub(int n1[],int n2[],int n3[]);
bool comp(int n1[],int n2[]);void mul(int n1[],int k,int n3[]);
void mul(int n1[],int n2[],int n3[]);void div(int n1[N],int k,int n3[]);
int main(){//1.读入cin>>str1>>str2;//2.存储转化transfer(str1,num1);transfer(str2,num2);//3.计算
//    add(num1,num2,num3);//3.减法
//    if(comp(num1,num2)){
//        sub(num1,num2,num3);
//        print(num3);
//    }else{
//        sub(num2,num1,num3);
//        cout<<"-";
//        print(num3);
//    }//3.乘法:高*低
//    mul(num1,100,num3);
//    mul(num1,num2,num3);
//    print(num3);div(num1,99,num3);print(num3);return 0;
}void transfer(string s, int n[]){int len = s.size();n[0] = len;//操作数的长度;for (int i = 0; i < len ; ++i) {n[i+1] = s[len - 1 - i] - '0';}
}void print(int n[]){for (int i = n[0]; i >= 1 ; i--) {cout<<n[i];}
}/*** n1 + n2 -> n3* @param n1* @param n2* @param n3*/
void add(int n1[],int n2[],int n3[]){int d[N] = {0};int len = max(n1[0],n2[0]);for (int i = 1; i <= len ; ++i) {d[i] += n1[i] + n2[i];d[i + 1] = d[i] / 10;d[i] = d[i] % 10;}//4.处理前导0int l = len + 1;while(d[l] == 0 && l > 1){l --;}d[0] = l;memcpy(n3,d, N * sizeof(int));
}void sub(int n1[],int n2[],int n3[]){int d[N] = {0};int len = n1[0];for(int i = 1;i <= len;i++){if(n1[i] < n2[i]){n1[i + 1] --;n1[i] += 10;}d[i] = n1[i] - n2[i];}int l = len;while(d[l] == 0 && l > 1){l--;}d[0] = l;memcpy(n3,d,N * sizeof(int));
}bool comp(int n1[],int n2[]){if(n1[0] != n2[0]){return n1[0] > n2[0];}else{int len = n1[0];for (int i = len; i >= 1 ; i--) {if(n1[i] != n2[i]){return n1[i] > n2[i];}}return true;}
}/*** 高精度*低精度* @param n1* @param k* @param n3*/
void mul(int n1[],int k,int n3[]){int d[N] = {0};int len = n1[0];for (int i = 1; i <= len ; ++i) {d[i] += n1[i] * k;d[i + 1] = d[i] / 10;d[i] = d[i] % 10;}//处理进位int l = len + 1;while (d[l] >= 10){d[l + 1] = d[l] / 10;d[l] = d[l] % 10;l++;}//前导0while(d[l] == 0 && l > 1){l--;}d[0] = l;memcpy(n3,d,N * sizeof(int));
}void mul(int n1[],int n2[],int n3[]){int d[N] = {0};//n1[i] * n2[j]结果放在d[i+j-1]for (int i = 1; i <= n1[0] ; ++i) {for (int j = 1; j <= n2[0] ; ++j) {int t = i + j - 1;d[t] += n1[i] * n2[j];d[t + 1] += d[t] / 10;d[t] = d[t] % 10;}}int l = n1[0] + n2[0];while(d[l] == 0 && l > 1){l -- ;}d[0] = l;memcpy(n3,d, N * sizeof(int));
}void div(int n1[N],int k,int n3[]){int d[N] = {0};int r = 0;for (int i = n1[0]; i >= 1 ; i--) {int sum = r * 10 + n1[i];d[i] = sum / k;r = sum % k;}//前导0int l = n1[0];while(d[l] == 0 && l > 1){l -- ;}d[0] = l;memcpy(n3,d,N * sizeof(int));
}

下面来详细讲解  

加法高精度

 加法

两个正整数相加,c数组=a数组+b数组(注:a[1]表示a数据的个位),对应位置相加,得到的新数字如果超过9,把个位留下,高位进上去,完全模拟加法的竖式运算,注意各位是从数组下标1开始的,运用如下代码。

/**
*
* @param a 加法
* @param b 加数
* @param c 和
* @param len 数组c的长度
*/
void add(int a[],int b[],int c[],int len){int d[len]={0};int m=max(a[0],b[0]);for(int i=1;i<=m;i++){d[i]=a[i]+b[i];d[i+1]=d[i]/10; //进位d[i]=d[i]%10; //取进位后余下的数}memcpy(c,d,len* sizeof(int));
}

去掉计算结果中最高位的0,因为两数相加,可能不产生进位,因此需要把这种情况下最高位的0去掉,其实就是减小和的长度。

//与上面的add函数相比,多了去掉高位0的操作
/**
*
* @param a 加法
* @param b 加数
* @param c 和
* @param len 数组c的长度
*/
void add(int a[],int b[],int c[],int len){int d[len]={0};int m=max(a[0],b[0]);for(int i=1;i<=m;i++){d[i]=a[i]+b[i];d[i+1]=d[i]/10; //进位d[i]=d[i]%10; //取进位后余下的数}int l=m+1;while(d[l]==0&&l>1){l--;}d[0]=l;memcpy(c,d,len* sizeof(int));
}

输出结果

void printResult(int c[]){for(int i=c[0];i>=1;i--){cout<<c[i];}
}

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int a[2000],b[2000],c[2000];
char al[2000],bl[2000];
int main(){int la,lb,lc,x=0;gets(al); gets(bl);la=strlen(al); lb=strlen(bl);for(int i=0;i<=la-1;++i) a[la-i]=al[i]-48;for(int i=0;i<=lb-1;++i) b[lb-i]=bl[i]-48;lc=1;while(lc<=la||lc<=lb){c[lc]=a[lc]+b[lc]+x;x=c[lc]/10;c[lc]%=10;lc++;}c[lc]=x;while(c[lc]==0) lc--;for(int i=lc;i>=1;--i) cout<<c[i];cout<<endl;return 0;
}

减法高精度

比较数组a和数组b的大小从而确定结果的正负号。

两个正整数相减,a数组=大a数组-小b数组,通常情况下,需要比较参与运算的两个整数的大小,通过大数减小数,模拟普通的减法,从低位开始对应的减,不足就向高位借一。

//比较两个数的大小,使用大数减去小数
bool compare(int a[],int b[]){if(a[0]!=b[0]){return a[0]>b[0];}else{for(int i=a[0];i>=1;i--){if(a[i]!=b[i]){return a[i]>b[i];}}return 1;}
}

使用大数减小数,并且去掉最高位的0。

/**
*
* @param a
* @param b a,b为参与计算的两个数
* @param c 差
* @param len 数组c的长度
*/
void sub(int a[], int b[], int c[], int len) {int d[len] = {0};for (int i = 1; i <= a[0]; i++) {if (a[i] < b[i]) {a[i] += 10;a[i + 1]--;}d[i] = a[i] - b[i];}int l = a[0];while (d[l] == 0 && l > 1) {l--;}d[0] = l;memcpy(c, d, len * sizeof(int));
}

打印输出结果

void printResult(int c[]){if(!compare(a,b)){cout<<"-";}for(int i=c[0];i>=1;i--){cout<<c[i];}
}

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char s1[10001],s2[10001],n[10001];
int a[10001],b[10001];
int main(){scanf("%s",s1); scanf("%s",s2);if(strlen(s1)==strlen(s2)){cout<<"0";}else if(strlen(s1)<strlen(s2)||strlen(s1)==strlen(s2)&&strcmp(s1,s2)<0){strcpy(n,s1);strcpy(s1,s2);strcpy(s2,n);printf("-");}int len1=strlen(s1),len2=strlen(s2);for(int i=len1-1;i>=0;--i) a[len1-(i+1)+1]=s1[i]-'0';for(int i=len2-1;i>=0;--i) b[len2-(i+1)+1]=s2[i]-'0';for(int i=1;i<=len1;++i){a[i]-=b[i];if(a[i]<0) a[i]+=10,a[i+1]--;}while(! a[len1]) len1--;for(int i=len1;i>=1;--i) printf("%d",a[i]);return 0;
}

乘法高精度

 乘法

这里有2种方法:

1
一大正整数乘以小正整数,即高精度数乘以一个整型数,c数组=a数组*k;
同加法类似,每一位都乘以k,再加上之前的进位,如果新得到的数字超过了10,那么个位留下,高位进上去。

/**
*
* @param a 被乘数
* @param k 乘数
* @param c 积
* @param len 数组c的长度
*/
void multipy(int a[],int k,int c[],int len){int d[len]={0};for(int i=1;i<=a[0];i++){d[i]+=a[i]*k;d[i+1]=d[i]/10;d[i]=d[i]%10;}int p=a[0]+1;//防止出现大于10的位while(d[p]>=10){d[p+1]=d[p]/10;d[p]=d[p]%10;p++;}
}

去除最高位的0,首先需要确定这两个数相乘可能的最大位数长度:

//计算k的位数
int f=k;
int size=0;
while(f!=0){size++;f/=10;
}
//size是乘数k的位数,乘积的长度
int l=a[0]+size;

完整的乘法函数

/**
*
* @param a 被乘数
* @param k 乘数
* @param c 积
* @param len 数组c的长度
*/
void multipy(int a[],int k,int c[],int len){int d[len]={0};for(int i=1;i<=a[0];i++){d[i]+=d[i]+a[i]*k;d[i+1]=d[i]/10;d[i]=d[i]%10;}int l=a[0]+1;int t=d[l];while(t!=0){d[l]=t%10;t/=10;l++;}
//去除前导0while(d[l]==0&&l>1){l--;}d[0]=l;memcpy(c,d,len* sizeof(int));
}

2
两大正整数相乘,c数组=a数组*b数组
模拟普通乘法竖式计算。

/**
*
* @param a 被乘数
* @param b 乘数
* @param c 乘积
* @param len 数组c的长度
*/
void multiply(int a[],int b[],int c[],int len){int d[len]={0};for(int i=1;i<=a[0];i++) {for (int j = 1; j <= b[0]; j++){d[i + j - 1] = a[i] * b[j] + d[i + j - 1];d[i+j]+= d[i + j - 1] / 10;//进位d[i + j - 1] = d[i + j - 1] % 10;}}int l=a[0]+b[0];while(d[l]==0&&l>1){l--;}d[0]=l;
//数组d拷贝导数组cmemcpy(c,d,len* sizeof(int));
}

输出结果

void printResult(int c[]){for(int i=c[0];i>=1;i--){cout<<c[i];}
}

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
char a2[1001],b2[1001];
int a[1001],b[1001],s,ss,s3,x,c[10001];
int main(){gets(a2);gets(b2);s=strlen(a2);ss=strlen(b2);for(int i=0;i<=s-1;i++)a[s-i]=a2[i]-'0';for(int i=0;i<=ss-1;i++)b[ss-i]=b2[i]-'0';for(int i=1;i<=s;i++){x=0;for(int j=1;j<=ss;j++){c[i+j-1]=a[i]*b[j]+x+c[i+j-1];x=c[i+j-1]/10;c[i+j-1]%=10;}c[i+ss]=x;}s3=s+ss;while(c[s3]==0&&s3>1)s3--;for(int i=s3;i>=1;i--) cout<<c[i];cout<<endl;return 0;
} 

除法高精度

 除法

这里也有2种方法:

1

大正整数除以小正整数,c数组=a数组÷b数,模拟除法竖式计算

/**
*
* @param a 被除数
* @param k 除数
* @param c 商
* @param l
*/
void divide(int a[],int k,int c[],int len){int d[len]={0};int x=0; //从高位开始除for(int i=a[0];i>=1;i--){d[i]=(x*10+a[i])/k;x=(x*10+a[i])%k;}
//计算k的位数int f=k;int size=0;while(f!=0){size++;f/=10;}
//size是成数k的位数int l=max(a[0]-size+1,1);
//去除前导0while(d[l]==0&&l>1){l--;}d[0]=l;
//把数组d的数据拷贝给cmemcpy(c,d,len* sizeof(int));
}

 

2

大正整数除以小正整数,c数组=a数组÷b数组

找到运算结果的最高位,从最高位一直循环到个位:

for(int i=a[0]-b[0]+1;i>=1;i--){//a[0]-b[0]+1运算结果的最高位
//除法运算
}

数组a从最高位到当前位与数组b进行比较

/**
* 比较大小
* @param a 被除数
* @param b 除数
* @param current 从最高位数到当前位置
* @return
*/
bool compareab(int a[],int b[],int current){if(a[0]-current+1>b[0]){return true; //大}else if(a[0]-current+1<b[0]){return false;//小}else{for(int i=a[0],j=b[0];i>=current;i--,j--){if(a[i]==b[j]){continue;}else{return a[i]>b[j];}}return 1;}
}

数组a从最高位到当前位减数组b

/**
* 减法
* @param a 被除数
* @param b 除数
* @param current 从最高位数到当前位置
* @return
*/
void deduce(int a[],int b[],int current){for(int i=current,j=1;i<=a[0];i++,j++){if(a[i]<b[j]){a[i]+=10;a[i+1]--;}a[i]=a[i]-b[j];}int len=a[0]; //减完以后把最高位的0去掉while(a[len]==0){len--;}a[0]=len; //
}

补充前面循环中的除法处理代码:

/**
*
* @param a
* @param b
* @param c
* @param len 数组a和数组c的长度,通常情况下我们把a,b,c三个数组的长度都设置成相同
*/
void divide(int a[],int b[],int c[],int len){int d[len]={0};int a1[len];
//使用a1进行计算,因为在计算过程中,被除数会被改变,因此拷贝一个数组参与运算memcpy(a1,a,len* sizeof(int));d[0]=1;//防止输入的被除数小于除数,无输出结果。for(int i=a[0]-b[0]+1;i>=1;i--){int t=0;while(compareab(a1,b,i)){deduce(a1,b,i);t++;}d[i]=t;}int l=max(a[0]-b[0]+1,1);
//去除前导0while(d[l]==0&&l>1){l--;}d[0]=len;
//把数组d的数据拷贝给cmemcpy(c,d,len* sizeof(int));
}

输出结果

void printResult(int c[]){for(int i=c[0];i>=1;i--){cout<<c[i];}
}

代码:

#include<iostream>
#include<cstring>
using namespace std;
int a[100],b[100],c[100];
int compare(int a[],int b[])
{  int i;  if(a[0]>b[0])  return 1;  if(a[0]<b[0])  return -1;  for(i=a[0];i>0;i--){  if(a[i]>b[i])  return 1;  if(a[i]<b[i])  return -1;  }  return 0;
}  void subduction(int a[],int b[])
{  int flag;  int i;  flag=compare(a,b);  if(flag==0){  a[0]=0;  return;  }  if(flag==1){  for(i=1;i<=a[0];i++)  {  if(a[i]<b[i]) {  a[i+1]--;  a[i]+=10;  }  a[i]-=b[i];  }  while(a[0]>0&&a[a[0]]==0)  a[0]--;  return;  }
}
int main()
{  char str1[100],str2[100];  int i,j;  memset(a,0,sizeof(a));  memset(b,0,sizeof(b));  memset(c,0,sizeof(c));  cin>>str1>>str2;  a[0]=strlen(str1);  b[0]=strlen(str2);  for(i=1;i<=a[0];i++)  a[i]=str1[a[0]-i]-'0';  for(i=1;i<=b[0];i++)  b[i]=str2[b[0]-i]-'0';  int temp[100];  c[0]=a[0]-b[0]+1;  for(i=c[0];i>0;i--)  {  memset(temp,0,sizeof(temp));  for(j=1;j<=b[0];j++)temp[j+i-1]=b[j];  temp[0]=b[0]+i-1;  while(compare(a,temp)>=0)  {  c[i]++;  subduction(a,temp);  }  }  while(c[0]>0&&c[c[0]]==0) c[0]--;  if(c[0]==0) cout<<0<<endl;  else  {  for(i=c[0];i>0;i--)  cout<<c[i];  cout<<endl;  }  if(a[0]==0) cout<<0<<endl;  else  {  for(i=a[0];i>0;i--)  cout<<a[i];  cout<<endl;  }  return 0;
}

注意除以0的情况!!

高精度算法 万字详解(C++)相关推荐

  1. 万字详解5G车联网技术

    车路协同.车联网.智慧交通.智能网联车.自动驾驶.无人驾驶.高精度地图资料汇总与整理 车路协同优质资料整理地址: 语雀:车路协同.自动驾驶.车联网.智能网联车 · 语雀 (yuque.com) 因阿里 ...

  2. JVM---垃圾收集器(万字详解)

    垃圾收集器万字详解 垃圾回收器 垃圾收集器万字详解 前言 垃圾收集器说明与发展史 垃圾收集器简要说明 垃圾收集器发展史 垃圾收集器的分类 衡量垃圾收集器性能的指标 不同的垃圾收集器概述 7款经典的垃圾 ...

  3. [Python从零到壹] 十一.数据分析之Numpy、Pandas、Matplotlib和Sklearn入门知识万字详解(1)

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  4. [论文阅读] (06) 万字详解什么是生成对抗网络GAN?经典论文及案例普及

    <娜璋带你读论文>系列主要是督促自己阅读优秀论文及听取学术讲座,并分享给大家,希望您喜欢.由于作者的英文水平和学术能力不高,需要不断提升,所以还请大家批评指正,非常欢迎大家给我留言评论,学 ...

  5. 推荐系统整体架构及算法流程详解

    省时查报告-专业.及时.全面的行研报告库 省时查方案-专业.及时.全面的营销策划方案库 知识图谱在美团推荐场景中的应用实践 搜索场景下的智能实体推荐 机器学习在B站推荐系统中的应用实践 小红书推荐系统 ...

  6. 万字详解什么是生成对抗网络GAN

    摘要:这篇文章将详细介绍生成对抗网络GAN的基础知识,包括什么是GAN.常用算法(CGAN.DCGAN.infoGAN.WGAN).发展历程.预备知识,并通过Keras搭建最简答的手写数字图片生成案. ...

  7. [Python从零到壹] 十五.文本挖掘之数据预处理、Jieba工具和文本聚类万字详解

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  8. CORDIC算法原理详解及其Verilog实现

    CORDIC算法原理详解及其Verilog实现 本文的verilog代码 链接:https://pan.baidu.com/s/1GGbRjxO5CxoIODQAg1l6Lw 提取码:jo0h *本文 ...

  9. [Python从零到壹] 五十一.图像增强及运算篇之图像灰度直方图对比分析万字详解

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  10. [Python图像处理] 三十三.图像各种特效处理及原理万字详解(毛玻璃、浮雕、素描、怀旧、流年、滤镜等)...

    此文转载自:https://blog.csdn.net/Eastmount/article/details/111568397#commentBox 该系列文章是讲解Python OpenCV图像处理 ...

最新文章

  1. Android UI设计与开发】第03期:引导界面(三)仿微信引导界面以及动画效果
  2. 在emu8086中学习汇编语言加减法程序
  3. Lesson 5.分类模型决策边界与模型评估指标
  4. C++中的指针与引用
  5. [JUC-4]ThreadPoolExecutor源码分析
  6. 20145227鄢曼君《网络对抗》Web安全基础实践
  7. DateUtils.paraseDate(String sDate,String[] parasePatterns);转换时间不对,pattern数组顺序
  8. 如何在Java中将字节数组转换为InputStream和OutputStream
  9. OJ1061: 顺序输出各位数字(C语言)(谈程序优化问题及pow函数耗时问题)
  10. linux系列之-—01 shell编程笔记
  11. Java关键字与保留字
  12. 帆软 在线Cron表达式
  13. GAN评价指标代码(FID、LPIPS、MS-SSIM)
  14. 网课答案查询单页源码+免费题库API接口
  15. 程序员有哪些类型,分别薪资是多少,带你一起走进程序员的大门
  16. Android使用Bugly实现静默安装/自动安装app
  17. 坦克大战第一阶段代码
  18. 活化N-羟基琥珀酰亚胺酯疏水染料CAS: 201998-61-0,BDP 576 NHS溶于极性有机溶剂该试剂是染料的活化N-羟基琥珀酰亚胺酯,与伯氨基和仲氨基具有反应性。
  19. 高盛:DeFi 的互操作性可能会增加系统性风险
  20. 【华为OJ】【067-求最小公倍数】

热门文章

  1. 通过python读取ini配置文件
  2. Shader预处理宏、内置状态变量、多版本编译等
  3. 运维自动化之zabbix(添加Graph screen)(3)
  4. 残酷的生命,严峻的人生,短暂的美好
  5. Apache Mahout的Taste基于Hadoop实现协同过滤推荐引擎的代码分析
  6. Struts2实现通过浏览器返回一个helloworld页面给用户
  7. c#虹软2.0免费人脸识别 实例
  8. vue学习项目之去哪儿网笔记
  9. NoSQL数据库的四大分类及分析
  10. 类似QQ下拉出现搜索