高精度算法
1.高精度数是什么?
高精度俗称大数,大指的不是数值大,不但几千亿几百亿是高精度数,小数点几百位或者更多位也是高精度数。
2.高精度数的存储
我们该如何存储高精度数呢?这里我们采用字符数组来存储高精度数字。把高精度数字拆开,按一位一位的或者几位几位存储到一个数组当中,用一个数组来代表一个数字。
3.高精度数的输出
当我们讲数据存储进去之后如何输出呢?直接输出数组吗?显然如果我们这样做输出出来的是一个由数字组成的字符串,达不到要求。那么这里我们就要用到字符型的数字转成数字。具体实现代码如下:
#include <iostream>
#include <cstring>
using namespace std;
int main(){
char a[1001];
cin>>a;
int len=strlen(a);
for(int i=0;i<len;i++){
cout<<a[i]-'0';
}
return 0;
}
3.高精度数的运算
3.1高精度加法
 ;我们把2个高精度数字相加分为一下几种情况,由浅入深。
3.1.1位数相同且无进位
这种情况比叫简单,只要转为int型后,按位相加就可以了。
#include<iostream>
#include <cstring>
using namespace std;
int main(){
char a[1001]={},b[1001]={};
gets(a);
gets(b);
int len=strlen(a);
for(int i=0;i<len;i++){
cout<<((a[i]-'0')+(b[i]-'0'));
}
return 0;
}
3.1.2位数不一定同且无进位
这种情况首先需要先对齐再运算。这里我们采用字符数组转化位整型数组时逆序输出。
#include<iostream>
#include <cstring>
#include <stack>
using namespace std;
int main(){
stack<int> s;
char a[1001]={},b[1001]={};
int add1[1001]={},add2[1001]={};
gets(a);
gets(b);
int lena=strlen(a);
int lenb=strlen(b);
int p=lena,q=lenb;
for(int i=0;i<lena;i++){
add1[--p] =a[i]-'0';
}
for(int i=0;i<lenb;i++){
add2[--q] =b[i]-'0';
}
int len=(lena>lenb?lena:lenb);
for(int i=0;i<len;i++){
s.push(add1[i]+add2[i]);
}
while(!s.empty()) {
cout<<s.top();
s.pop();
}
return 0;
}
3.1.3位数不一定同且可能有进位
如果是这种情况,只要在前面的代码基础中两个高精度按位相加再加一个进位数就可以了。具体可看代码注释
#include<iostream>
#include <cstring>
#include <stack>
using namespace std;
int main(){
char a[1001]={},b[1001]={};
int add1[1001]={},add2[1001]={},result[1001]={};
gets(a);
gets(b);
int lena=strlen(a);
int lenb=strlen(b);
int p=lena,q=lenb;
//高精度数逆序
for(int i=0;i<lena;i++){
add1[--p] =a[i]-'0';
}
//高精度数逆序
for(int i=0;i<lenb;i++){
add2[--q] =b[i]-'0';
}
//准备工作完成,开始相加
int x=0,i=0;//x用来存储当前的进位情况
int max=(lena>lenb?lena:lenb);
while(i<max) {
result[i]=(add1[i]+add2[i]+x)%10;//存储位上的值
x=(add1[i]+add2[i]+x)/10;//更新进位
i++;
}
//最高位是否溢出
if(x!=0){
result[i]=x;
}
else{
i--;
}
for(int j=i;j>=0;j--){
cout<<result[j];
}
return 0;
}
3.2高精度减法
3.2.1位数相同无借位
思路
数据处理:
1.用字符数组存储高精度数
计算:
1.和加法类似,遍历字符数组,转化为数字后进行相减
2.如果出现类似结果为00000100的情况,还要处理前缀的0
代码实现:
#include<iostream>
#include<cstring>
using namespace std;
int main(){
//输入
char a[1001]={};
char b[1001]={};
int result[1001]={};
cout<<"输入被减数";
gets(a);
cout<<"输入减数" ;
gets(b);
int len=strlen(a);
//计算
for(int i=0;i<len;i++){
result[i]=(a[i]-'0')-(b[i]-'0');
}
int i=0;
//去0
while(i<len-1&&result[i]==0){//这里的i<len-1而不是i<len 是考虑到存在被减数和减数相同时,削去前缀0
i++;
}
//输出
for(int j=i;j<len;j++){
cout<<result[j];
}
return 0;
}
3.2.2 位数不同无借位
思路
数据处理:
1.用字符串存储高精度数
2.逆序对齐
计算
1.相减,结果再逆序
2.去0输出
这次我们尝试用STL来写
代码:
#include<iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
//输入
string a,b;
cin>>a>>b;
vector<int> c;
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
int min=(a.size()<b.size()?a.size():b.size());
for(int i=0;i<min;i++){
c.insert(c.begin(),(a[i]-'0')-(b[i]-'0'));
}
for(int i=min;i<a.size();i++){
c.insert(c.begin(),a[i]-'0');
}
//去0
int i=0;
while(i<c.size()&&c[i]==0){//这里的i<len-1而不是i<len 是考虑到存在被减数和减数相同时,削去前缀0
i++;
}
for(;i<c.size();i++){
cout<<c[i];
}
return 0;
}
3.2.3位数不一定相同可能借位
之前默认了减数均小于被减数,这次尝试实现出来
思路:
1.先比较2个数的大小
2.逆序后相减,注意借位
3.得出结果
#include<bits/stdc++.h>
using namespace std;
bool compare(string a,string b){
int a_size=a.size();
int b_size=b.size();
//根据字符串长度区分3种情况
if(a_size>b_size){
return true;
}
else if(a_size<b_size){
return false;
}
else if(a_size==b_size){
int i=0;
while(a[i]==b[i]&&i!=a_size-1){
i++;
}
if(a[i]>=b[i]){
return true;
}
else{
return false;
}
}
}
void sub(string a,string b){
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
//借位x初始为0
int result[100];
int min=b.size(),x=0,k=0,temp=0;
//两数相减
for(int i=0;i<min;i++){
temp=(a[i]-'0')-(b[i]-'0')-x;
//按位求值
if(temp<0){
temp=temp+10;
x=1;
result[k++]=temp;
}
else{
x=0;
result[k++]=temp;
}
}
for(int i=min;i<a.size();i++){
temp=(a[i]-'0'-x);
if(temp<0){
temp=temp+10;
x=1;
result[k++]=temp;
}
else{
x=0;
result[k++]=temp;
}
}
reverse(result,result+k);
//削去0
int i=0;
while(result[i]==0&&i<k-1){
i++;
}
for(int j=i;j<k;j++){
cout<<result[j];
}
}
int main(){
string a,b;
cin>>a>>b;
if(compare(a,b)){
sub(a,b);
}
else{
sub(b,a);
}
return 0;
}
3.3高精度乘法
3.3.1高精度数乘个位数
#include<bits/stdc++.h>
using namespace std;
void HighPrecision(string a,int b,int result[],int &k){
//72563 * 4
int len=a.size();
len--;
int temp=0,x=0;//temp临时变量,x代表进制
for(int i=len;i>=0;i--){
temp=(a[i]-'0')*b+x;
result[k++]=temp%10;
x=temp/10;
}
reverse(result,result+k);
}
int main(){
int result[200];
string a;
int b,k=0;
cin>>a>>b;
HighPrecision(a,b,result,k);
//输出
for(int i=0;i<k;i++){
cout<<result[i];
}
return 0;
}
3.3.2 高精度数乘高精度数
思路:当了解高精度数乘单数的思想后我们就可以很简单的想出高精度乘高精度数的算法,无非就是不断调用1的函数,将结果按位相加。
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
int main(){
string a,b;
cin>>a>>b;
//数据处理
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
int len_a=a.size();
int len_b=b.size();
int n=len_a+len_b;
vector<int> c;
for(int i=0;i<n;i++){
c.insert(c.begin(),0);
}
//逐位相乘
for(int i=0;i<len_a;i++){
for(int j=0;j<len_b;j++){
c[i+j]=(a[i]-'0')*(b[j]-'0')+c[i+j];
}
}
//处理进位
for(int i=0;i<n-1;i++){
//下面的2句顺序不能反
c[i+1]=c[i]/10+c[i+1];
c[i]=c[i]%10;
}
reverse(c.begin(),c.end());
//去前缀0
int i=0;
while(i<n-1&&c[i]==0) {//这里范围取i<n-1是考虑结果为0的情况)
i++;
}
for(;i<c.size();i++){
cout<<c[i];
}
}