一,高精度到底解决的是什么问题?
所谓的高精度算法其实解决的就是简单的加减乘除运算,但是为什么我们称他们为一类算法呢,在C语言中不是有相关的运算符可以进行运算吗?这需要我们知道一点,在C语言中的运算固然是可以进行的,但是他是有一定的限制条件存在的,我们知道在进行运算的时候我们要借助相关的变量来存储数据来进行运算,long long 变量是最大的整数性变量,他能够开到的最大值也不过1018 ,如果我们要进行更大数值的运算我们就无法进行处理了,所以我们提出了高精度算法。
高精度指的不仅仅是向下(小数点向右)的精度,而且还有向上(小数点向左)的精度
二,高精度算法
1,高精度算法的思想
高精度加减乘除的算法思想其实都是一样的,我们无法处理数据,我们就要想人们处理数据是怎么进行的,以高精度加法为例子,我们人们在进行加法运算的时候,是使用逐步进位的方式求解的,我们就可以从这个方向来入手,手写加法,首先要找到突破口再进行整个数据的处理。高精度算法的核心思想就是化多为1:把一个很长的数值分成一个值,一个值的进行运算,这样我们的问题就非常简化了,就是一个是加减乘除每个算法的特性运算,另一个就是如何把这些高精度数据分开的通用解。
2, 高精度数据的存储
高精度数据有很多存储办法,但是我们为了简化操作最终选择了,vector数组存储的方法,首先,我们读入高精度数据的时候,我们要使用string数据类型进行读入,然后我们把些数据一个一个读入vector中,要保证push vector的时候是从低位向高位压入的,因为只有这样才能保证数值的对应关系,并且方便进位。
整个操作是比较简单的,但是需要注意的就是, 这个操作的str 中的数据需要一些处理才能被压入,因为str 中的数字是字符类型的。我们要压进去的是数字才能进行运算,故我们要进行一个简单的str[i] - ‘0’,完成这个操作再进行就可以了。
补充的vector基础操作
定义: vector <数据类型> 变量名 ;
调用: (下标 ) 从0开始 ,到 n - 1
大小: B.size() 返回大小
压入: C.push_back()
完成数据的低位压入
#include <iostream>
#include <string>
#include <vector>
using namespace std ;
int main ()
{
string a;
vector <int> A;
cin >> a;
for(int i = a.length() - 1 ; i >= 0 ; i -- )
A.push_back(a[i] - '0');
//存储:1.反存储 , 2.减去'0'
for(int i = 0 ; i < A.size() ; i ++ )
cout << A[i] ;
puts("") ;
return 0 ;
}
三 , 高精度加法
1,算法思路
首先我们知道我们已经把数据按低位存储了,我们怎么把这个大的运算拆解成一个一个小的运算来进行求解?我们就要从原来的加法思路中寻找解决办法,我们可以按照进位的方法每次运行第i个运算,并且加上上一位的进位,然后我们存入到一个新的数组中,当两边都为空的时候我们结束这个算法,当进位为1 的时候,我们为目标数组进一位,最后我们再返回数组就能完成这个操作
当然数组的输出也要逆位输出.
2,算法代码
#include <iostream>
#include <vector>
#include <string>
using namespace std ;
vector <int> add(vector<int> &A ,vector<int> &B)
//f1.&取地址运算能加快速度 , 能加上的时候尽量加上.
{
int t = 0 ;
//存数的指针
vector <int> C;
for(size_t i = 0 ; i < A.size() || i < B.size() ; i ++ )
{
if(i < A.size()) t += A[i] ;
if(i < B.size()) t += B[i] ;
C.push_back(t % 10);
t /= 10;
}
if(t) C.push_back(1) ;
return C ;
}
四,高精度减法
1,算法思路
经过高精度加法的学习,我们想到了这个算法实际上就是有一个类似指针的东西进行控制的,我们每次都依靠这个指针为我们目标数组赋一次值,解决高精度问题的关键实际上就是处理这个指针的问题。我们要思考这个减法的操作,减法的操作中我们知道会大-小 和 小-大 两种操作,如何完成这两种操作,我们可以把这两种化成一种,我们先判断一下这个是那种情况然后并成其中的一种情况进行处理。我们可以实现一下把A - B的操作,首先我们判断一下那个数大。
bool cmp (vector<int> &A , vector<int> &B)
{
if(A.size() != B.size()) return A.size() > B.size();
for(int i = A.size() - 1 ; i >= 0 ;i --)
if(A[i] != B[i])
return A[i] > B[i];
return true ;
}
完成这个操作之后,我们再在主函数上设定一个判断分支结构就能满足A > B。然后我们要完成减法的主体操作
vector <int> sub(vector <int> &A ,vector<int> &B)
{
int t = 0 ;
//指针为 t ,t代表当前A - B 的值
vector <int> C;
for(size_t i = 0 ; i < A.size() ; i ++ )
{
t += A[i] ;
//完成 + A
if(i < B.size() ) t -=B[i] ;
//完成 - B
C.push_back((t + 10) % 10 );
if(t >= 0) t = 0 ;
else t = -1 ;
//完成为下一位的赋值
}
while (C.size() > 1 && C.back() == 0) C.pop_back() ;
return C ;
}
接下来我们看一下整体的代码
#include <iostream>
#include <vector>
using namespace std;
bool cmp (vector<int> &A ,vector<int> &B )
{
if(A.size() != B.size() ) return A.size() > B.size() ;
for(int i = A.size() - 1; i >=0 ; i -- )
if(A[i] != B[i])
return A[i] > B[i] ;
return true ;
}
vector <int> sub(vector <int> &A , vector <int> &B)
{
vector <int> C;
for(int i = 0 , t = 0;i <= A.size() - 1; i ++ )
{
t = A[i] - t ;
if(i < B.size() ) t -= B[i];
C.push_back( ( t + 10 ) % 10 );
if(t<0) t=1;
else t=0;
}
while (C.size ()>1 && C.back()==0) C.pop_back();
return C;
}
int main ()
{
string a , b ;
vector <int> A ,B ,C ;
cin >> a >> b ;
for(int i = a.length() - 1; i >= 0 ; i --)
A.push_back(a[i] - '0');
for(int i = b.length() - 1 ; i >= 0 ; i --)
B.push_back(b[i] - '0');
if(cmp(A,B))
{
auto C=sub(A,B);
for(int i=C.size()-1;i>=0;i--) cout << C[i];
}
else
{
auto C=sub(B,A);
cout<<"-";
for(int i=C.size()-1;i>=0;i--) cout<<C[i];
}
return 0;
}
五,高精度乘法
1,算法思路
高精度乘法跟前两个比较可以说是更加的简单的,大致是延续了高精度加法的算法思路,这个高精度乘法按道理来说并不能算是一个完全的高精度乘法,这个是一个高精度 * 低精度 的一种算法。这个算法里面涉及一个删除前导零的算法和一个前文我们所说的类似指针的一个算法,这个指针是储存每次的乘法的值,每次输出末尾。
2,代码
#include <iostream>
#include <vector>
using namespace std ;
vector<int> mul (vector<int> & A ,int b)
{
int t = 0 ;
//相当于整个题目的指针
vector <int> B ;
for(int i = 0 ; i < A.size() || t ; i ++)
{
if(i < A.size()) t += A[i] * b ;
B.push_back(t % 10);
t /= 10 ;
}
while (B.size() > 1 && B.back() == 0) B.pop_back();
return B ;
}
int main ()
{
int a ;
string b ;
vector <int> A , B;
cin >> b >> a ;
for(int i = b.length() - 1 ; i >= 0 ; i -- )
A.push_back(b[i] - '0');
B = mul(A,a);
for(int i = B.size() - 1 ;i >= 0 ; i --)
cout << B[i] ;
return 0 ;
}
六,高精度除法
1,算法思路
首先这个算法不同于前几个算法,这个算法虽然是逆数据存储但是最后的时候还是从高位进行的运算。整个算法经过了两次反转,再说他的指针他的指针指向的是他的余数,每一阶段都指向每一阶段的余数,思想和乘法差不多
补充知识:为了删除前导零,我们要使用
algorithm 头文件中的 reverse 函数(使用迭代器)
2,代码
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std ;
vector <int> div(vector <int> &B ,int a ,int &r)
{
r = 0 ;
vector <int> C ;
for(int i = B.size() - 1 ; i >= 0 ; i -- )
{
r = r * 10 + B[i] ;
C.push_back(r / a);
r %= a ;
}
reverse(C.begin(),C.end());
while (C.back() == 0 && C.size() > 1 ) C.pop_back();
return C ;
}
int main ()
{
int a , r;
string b ;
cin >> b >> a ;
vector <int> B , C;
for(int i = b.size() - 1 ; i >= 0 ; i -- )
B.push_back(b[i] - '0');
C = div(B , a , r);
for(int i = C.size() - 1 ;i >= 0 ; i --)
cout << C[i] ;
cout << endl << r << endl;
return 0 ;
}