高精度算法

高精度算法

在C++中,数据的大小是有上限的,若要进行大位数整数的运算,就需要借助高精度运算算法。

注意

  1. 因为数据位数太大,所以只能用string类型变量来接收输入的数据。

  2. 由于处理进位方便、在数组尾部插入操作比在头部插入复杂度低等原因,所有数据应以倒序存储。

string s1,s2;
cin >> s1 >> s2;
vector<int> A,B;
for(int i = s1.size() - 1; i >= 0;i--)  A.push_back(s1[i]-'0');//注意要减'0'!!!
for(int i = s2.size() - 1; i >= 0;i--)  B.push_back(s2[i]-'0');

注意: 因为string中每个元素都是字符型,所以数据在倒序存入vector时需要-'0'

  1. 可以用vector数组来存储输入的数据,这样就不需要再维护一个数据的长度变量,而是可以直接调用vector.size()方法获取,在进行数组操作时也会更加灵活方便。
    • 在今后的算法学习中,如果一个数据长度不定而又需要使用它的长度,可以尝试使用vector数组存储。

1. 高精度加法

模板
vector<int> add(vector<int> &A, vector<int> &B)
{
    //始终保持形参A的位数形参大于B的位数
    if (A.size() < B.size()) return add(B, A);
	//C存储高精度加法和
    vector<int> C;
    //本来需要两个局部变量 一个存储进位 一个存储一位和
    //但是这两个变量可以合并,只需要存储进位t
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }
	//处理最高位进位
    if (t) C.push_back(t);
    return C;
}

注意

  • 为了简化判断条件,可以始终保持形参A的位数形参大于B的位数。
  • 可以将进位和一位和合并成一个变量。
  • 不要忘记处理最高位进位

2. 高精度减法

模板
// C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size(); i ++ )
    {	//同理,把借位和一位差合并成一个变量
        t = A[i] - t;
        if (i < B.size()) t -= B[i];
        //当t小于0时,push_back t + 10
        //当t大于等于0时,push_back t
        //push_back (t + 10) % 10 巧妙地把上述两种情况结合起来了
        C.push_back((t + 10) % 10);
        //判断借位情况
        if (t < 0) t = 1;
        else t = 0;
    }
	//处理前导0
    while (C.size() > 1 && C.back() == 0) 
        C.pop_back();
    return C;
}

注意

  • 使用这个模板时一定要保证形参A >= 形参B。为此,应在主程序中添加判断语句。
  • 不要忘记处理减法的前导0

3. 高精度乘法

模板
// C = A * b, A >= 0, b >= 0
vector<int> mul(vector<int> &A, int b)
{
    vector<int> C;

    int t = 0;
    //这里合并了两个循环
    for (int i = 0; i < A.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10);
        t /= 10;
    }
    
    /* 原本下面还需要一个循环
    while(t){
    	C.push_back(t % 10);
    	t /= 10;
    }
    */
	//处理前导0
    while (C.size() > 1 && C.back() == 0) 
        C.pop_back();

    return C;
}

注意

  • 乘法也可能会出现前导0!当有一个乘数是0时就会出现。
  • 当两个循环的循环体大部分相同时,可以试试将两个循环合并。

4. 高精度除法

模板
// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)
{
    vector<int> C;
    //除法要有两个返回值(商和余数),而C++的函数只能有一个返回值,所以余数只能以引用传递的方式返回
    r = 0;
    //要注意,除法和前面的运算不同,是从最高位开始出结果的。所以循环顺序和前面的运算相反。
    for (int i = A.size() - 1; i >= 0; i -- )
    {
        r = r * 10 + A[i];
        C.push_back(r / b);
        r %= b;
    }
    //为了和前面的运算输出(倒序输出)保持一致,要把商序列倒序输出
    reverse(C.begin(), C.end());
    //前导0处理
    while (C.size() > 1 && C.back() == 0) 
        C.pop_back();
    return C;
}

注意

  • 除法的运算顺序和其他几种运算不太一样,需要注意。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值