参考:https://blog.csdn.net/actioncms/article/details/105148549
一、本质
高精度算法的本质在于将复杂变为简单
实现的原理是小学学过的列式计算
将每一位进行逐步运算
二、代码
高精加
/*======================================
高精度加法
不考虑负数(高精减来处理负数)
字符接收再转为整数数组
注意颠倒,注意消除前置0
核心在于 a 数组 + b数组 = c数组
核心代码为:
c[i]+=a[i]+b[i];
c[i+1]=c[i]/10;
c[i]=c[i]%10;
=======================================*/
#include <iostream>
using namespace std;
string s1,s2;
int a[1000];
int b[1000];
int c[1001];
int main()
{
cin >>s1 >>s2;
int la=s1.length();
int lb=s2.length();
for (int i=0;i<la;i++)
{
a[la-i] = s1[i] - '0'; //转化接收
}
for (int i=0;i<lb;i++)
{
b[lb-i] = s2[i] - '0';
}
int lc = max(la,lb)+1; //c数组的长度
for (int i=1;i<=lc;i++)
{
c[i] += a[i] + b[i]; //核心代码
c[i+1] = c[i]/10;
c[i] = c[i]%10;
}
if (c[lc]==0 && lc>0) lc--; //消除前置0
for (int i=lc;i>0;i--)
{
cout <<c[i];
}
return 0;
}
高精减
/*=========================================
高精度减法
输入的也是两个正数
flag是对正负号的跟踪判断
comp函数还是需要深入理解下(判断是否换位)
==========================================*/
#include <iostream>
#include <string>
using namespace std;
string s1,s2;
string s3;
bool flag=0;
int a[10100],b[10100],c[10100];
bool comp(string a,string b)
{
int la=a.length();
int lb=b.length();
if (la!=lb) return la>lb;
else
{
for (int i=0;i<la;i++)
{
if (a[i]!=b[i])
{
return a[i]>b[i];
break;
}
}
}
}
int main()
{
cin >>s1 >>s2;
if (!comp(s1,s2))
{
s3=s1;
s1=s2;
s2=s3;
flag=1; //若换位则改变 flag
}
int la=s1.length();
int lb=s2.length();
for (int i=0;i<la;i++)
{
a[la-i]=s1[i]-'0';
}
for (int i=0;i<lb;i++)
{
b[lb-i]=s2[i]-'0';
}
int lc=max(la,lb); //与加法不同 c 数组的长度最多是 a,b中较长那个
for (int i=1;i<=lc;i++)
{
if (a[i]<b[i]) //借位判断
{
a[i+1]--; //不够则向上位借1
a[i]+=10; //本位+10
}
c[i]=a[i]-b[i];
}
while (c[lc]==0&&lc>1) lc--; //消除前置0,方法与高精加略有不同
if(lc==1&&c[0]==0) flag=0; //相减为0的情况下不输出 - 号
if(flag) cout <<"-";
for (int i=lc;i>0;i--)
{
cout <<c[i];
}
return 0;
}
高精乘
/*=========================================
高精乘
核心算法:(列式计算中找出的规律)
c[i+j-1] += a[i] * b[j];
c[i+j] += c[i+j-1]/10;
c[i+j-1] %= 10 ;
==========================================*/
#include <iostream>
#include <string>
using namespace std;
string s1,s2;
int a[2008],b[2008],c[2008];
int main()
{
int la,lb,lc;
cin >>s1 >>s2;
la=s1.length();
lb=s2.length();
for (int i=0;i<la;i++)
{
a[la-i]=s1[i]-'0';
}
for (int i=0;i<lb;i++)
{
b[lb-i]=s2[i]-'0';
}
lc=la+lb; //c 数组的位数不会超过其和
for (int i=1;i<=la;i++)
{
for (int j=1;j<=lb;j++)
{
c[i+j-1] += a[i]*b[j]; //核心算法
c[i+j] += c[i+j-1]/10; //进位
c[i+j-1] %= 10; //留位
}
}
if (c[lc]==0&&lc>0) lc--; //消除前置零
for (int i=lc;i>0;i--)
{
cout <<c[i];
}
return 0;
}
三、总结&感想
学习的道路上艰辛却又看不见终点
好在大家走的路都是相似的
前人铺垫好的
我们感谢、使用、完善
例如,在减法中存在一个借位判断
在之后可能就会遇到别的相似判断
附上一道题,洛谷 P1009 阶层之和(写一起主要是懒得再写一篇了 ps:洛谷是一个网站啦)
/*===============================
阶层之和很简单,一个循环就能搞定
但是只限于数目较小的时候
通过这一道题目来初步学习高精度算法
高精度就是说参与运算的数据和运算结果的范围
超出标准数据类型能表示的数据大小范围的运算
================================*/
/*================================
核心还是高精算法
关键还是把握整体思路
中间有一个判断
和借位判断类似
像是一个进位判断
================================*/
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int a[2000];
int b[2000];
int main()
{
a[1]=1;
int n;
cin >> n;
for (int i=1;i<=n;i++)
{
for (int j=1;j<100;j++) //50个二位数一下累乘位数不会超过100
{
a[j] *= i; //每一位先乘
}
for (int j=1;j<100;j++)
{
if (a[j]>9) //进位判断
{
a[j+1]+=(a[j]/10);
a[j] %= 10;
}
}
for (int k=1;k<100;k++)
{
b[k] += a[k]; //累加进入 b 数组
if (b[k]>9)
{
b[k+1] += (b[k]/10);
b[k] %= 10;
}
}
}
int ws=100; //消除前置0(定义出一个位数)
while(b[ws]==0) ws--;
for (int i=ws;i>0;i--)
{
cout <<b[i];
}
}