高精度算法总结

为什么要使用高精度?

很多人在刚接触高精度算法的时候可能和我有一样的疑问,明明用int或者再大一丢丢的longlong就能储存的数据,为什么非要用高精度算法。

这是因为普通基本数据类型存储数据的时候是有大小限制的,比如我们常用的int-->他的表示范围是(-2^31,2^31-1)大约是10^9数量级,那么如果我想表示10^11数量级的数字怎么办?有人说可以用longlong它大概是10^18次方量级,但如果我要存储的比10^18量级还大的数据怎么办?这也需要用高精度算法了

那么高精度算法是如何储存想10^11次方这样量级的数据的那,其实很简单,用的就是一个整型数组,因为我们知道如果我们的数组开在全局区的话,那么它的空间可以非常非常的大,反正你想表示的大数它肯定能存下。

初步了解了高精度的大概模样之后,我来介绍一下高精度算法的四大模块

一、高精度加法

高精度加高精度

算法的思路:

1.需要用字符数组去接收我们的高精度数

如果用整形数组去接收我们的高精度数,整形数组会认为他是一个数,把它都存储在下标0的位置,会溢出

所以必须用字符数组去接收,它会把高精度数看出多个字符的形式,而且还可以很轻松用strlen求出长度

2.把字符数组中的数据逆序传给整形数组

这样做的话可以模拟整形数组的第一位就是个位,第二位就是十位一次类推

因为我们在算加减乘的时候都是先算个位,然后十位,一次类推,这样做可以方便计算

3.计算相加后数据的长度

俩个数相加之后的长度最长也不会超过他俩长度的最大值+1

4.核心算法,模拟俩个数据相加

设a,b位整形数组存储的高精度数,c位俩个高精度数相加后的结果

那么

c[i]=a[i]+b[i]+c[i] //c的第i位应该等于a的第i位+b的第i位再加上第i位的进位

c[i+1]=c[i]/10;

c[i]=c[i]%10;

5.逆序输出

例题:

【题目描述】

求两个不超过200位的非负整数的和。

【输入】

有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。

【输出】

一行,即相加后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。

【输入样例】
22222222222222222222 33333333333333333333
【输出样例】
55555555555555555555

代码实现

#include <iostream>
​
using namespace std;
const int N = 2e2 + 5;
char sa[N], sb[N];
int a[N], b[N], c[N];
void CharToInt(char sa[], int a[]) {
    for (int i = 1; i <= a[0]; i++) {
        a[i] = sa[a[0] - i] - '0';
    }
}
void GJD_Add(int a[], int b[], int c[]) {
    for (int i = 1; i <= c[0]; i++) {
        c[i] = a[i] + b[i] + c[i];
        c[i + 1] = c[i] / 10;
        c[i] = c[i] % 10;
    }
}
void Delete_frontZero(int c[]) {
    while (c[0] >= 2 && c[c[0]] == 0) {
        c[0]--;
    }
}
void Show(int c[]) {
    for (int i = c[0]; i >= 1; i--) {
        cout << c[i];
    }
}
int main() {
    cin >> sa >> sb;//用字符数组接收高精度数
    a[0] = strlen(sa);//a[0]表示高精度数sa的位数
    b[0] = strlen(sb);//b[0]表示高精度数sb的位数
    CharToInt(sa, a);//把字符数组sa逆序转化位整形数组
    CharToInt(sb, b);//把字符数组sb逆序转化位整形数组
    c[0] = max(a[0], b[0]) + 1;//c长度
    GJD_Add(a, b, c);//模拟高精度加法
    Delete_frontZero(c);//删除前导0
    Show(c);//输出
    return 0;
}

二、高精度减法

高精度减高精度

算法思路:

1.前面和高精度加高精度一样
2.核心算法

设a,b位整形数组存储的高精度数,c位俩个高精度数相减后的结果

那么

先判断a[i]和b[i]的大小关系,如果a[i]<b[i]要借1当10用,向a借1

if (a[i] < b[i]) { a[i + 1]--;//借1 c[i] = a[i] - b[i] + 10;//当10 } else c[i] = a[i] - b[i];

例题:

【题目描述】

求两个大的正整数相减的差。

【输入】

共2行,第1行是被减数a,第2行是减数b(a > b)。每个大整数不超过200位,不会有多余的前导零。

【输出】

一行,即所求的差。

【输入样例】
9999999999999999999999999999999999999 9999999999999
【输出样例】
9999999999999999999999990000000000000
#include <iostream>
​
using namespace std;
const int N = 2e2 + 5;
char sa[N], sb[N];
int a[N], b[N], c[N];
void CharToInt(char sa[], int a[]) {
    for (int i = 1; i <= a[0]; i++) {
        a[i] = sa[a[0] - i] - '0';
    }
}
void GJD_reduce(int a[], int b[], int c[]) {
    for (int i = 1; i <= c[0]; i++) {
        if (a[i] < b[i]) {
            a[i + 1]--;//借1
            c[i] = a[i] - b[i] + 10;//当10
        }
        else
            c[i] = a[i] - b[i];
    }
}
void Delete_frontZero(int c[]) {
    while (c[0] >= 2 && c[c[0]] == 0) {
        c[0]--;
    }
}
void Show(int c[]) {
    for (int i = c[0]; i >= 1; i--) {
        cout << c[i];
    }
}
int main() {
    cin >> sa >> sb;
    a[0] = strlen(sa);
    b[0] = strlen(sb);
    CharToInt(sa, a);
    CharToInt(sb, b);
    c[0] = max(a[0], b[0]);
    GJD_reduce(a, b, c);
    Delete_frontZero(c);
    Show(c);
    return 0;
}

三、高精度乘法

高精度乘高精度

算法思路:

for (int i = 1; i <= a[0];i++) { for (int j = 1; j <= b[0];j++) { c[i + j - 1] += a[i] * b[j]; c[i + j] += c[i + j - 1] / 10; c[i + j - 1] = c[i + j - 1] % 10; } }

算法实现:

#include <iostream>
​
using namespace std;
const int N = 2e2 + 5;
char sa[N], sb[N];
int a[N], b[N], c[N];
void CharToInt(char sa[], int a[]) {
    for (int i = 1; i <= a[0]; i++) {
        a[i] = sa[a[0] - i] - '0';
    }
}
void GJD_Multiply(int a[], int b[], int c[]) {
    for (int i = 1; i <= a[0]; i++) {
        for (int j = 1; j <= b[0]; j++) {
            c[i + j - 1] += a[i] * b[j];
            c[i + j] += c[i + j - 1] / 10;
            c[i + j - 1] = c[i + j - 1] % 10;
        }
    }
}
void Delete_frontZero(int c[]) {
    while (c[0] >= 2 && c[c[0]] == 0) {
        c[0]--;
    }
}
void Show(int c[]) {
    for (int i = c[0]; i >= 1; i--) {
        cout << c[i];
    }
}
int main() {
    cin >> sa >> sb;
    a[0] = strlen(sa);
    b[0] = strlen(sb);
    CharToInt(sa, a);
    CharToInt(sb, b);
    c[0] = a[0] + b[0];
    GJD_Multiply(a, b, c);
    Delete_frontZero(c);
    Show(c);
    return 0;
}

高精度乘低精度

算法思路:

它的算法实现思路与之前的略有不同,之前是俩已经有数据的数组相乘保存再另一个数组里面

而他刚开始数组里面是空的,经过一次又一次的循环它里面的数据变成了高精度数据,但是与它相乘的始终都是低精度

核心算法:

假设刚开始a[0]长度位1,循环结束之后,jw进位数可能是一个很大的数,我们要把它平铺开!!!!!!!!核心!!!!!!!!!!

for (j = 1; j <= a[0]; j++) { a[j] = a[j] * i + jw; jw = a[j] / 10; a[j] = a[j] % 10; } while (jw > 0) { a[j++] = jw % 10; jw /= 10; a[0]++; }

例题:

【题目描述】

求1000010000以内n�的阶乘。

【输入】

只有一行输入,整数n�(0≤n≤100000≤�≤10000)。

【输出】

一行,即n!�!的值。

【输入样例】
4
【输出样例】
24
代码:
#include <iostream>
using namespace std;
const int N = 4e4 + 5;
char sa[N];
int a[N], len, n, jw, j;
int main() {
    cin >> n;//4
    len = 1;
    a[1] = 1;
    for (int i = 1; i <= n; i++) {
        jw = 0;
        for (j = 1; j <= len; j++) {
            a[j] = a[j] * i + jw;
            jw = a[j] / 10;
            a[j] = a[j] % 10;
        }
        while (jw > 0) {
            a[j++] = jw % 10;
            jw /= 10;
            len++;
        }
        while (len >= 2 && a[len] == 0) {
            len--;
        }
    }
    for (int i = len; i >= 1; i--) {
        cout << a[i];
    }
    cout << endl;
    return 0;
}

四、高精度除法

高精度除以高精度

略!!!!!!!

高精度除以低精度

核心算法:

模拟小学算术的过程可以得到

【题目描述】

输入一个大于0的大整数N,长度不超过100位,要求输出其除以13得到的商和余数。

【输入】

一个大于0的大整数,长度不超过100位。

【输出】

两行,分别为整数除法得到的商和余数。

【输入样例】
2132104848488485
【输出样例】
164008065268345 0

代码实现:

#include <iostream>
​
using namespace std;
const int N = 2e5 + 5;
char sa[N];
int a[N], c[N],lena,k;
int Chufa13(int a[],int c[]) {
    int x = 0;
    c[0] = a[0];
    for (int i = 1;i<=a[0];i++){
        c[i] = (x * 10 + a[i]) / 13;
        x = (x * 10 + a[i]) %13;
    }
    return x;
}
void Reverse(int c[]) {
    int i, j;
    for (i = 1, j = c[0]; j > i;j--,i++) {
        swap(c[i], c[j]);
    }
}
void DeleteZero(int c[]) {
    while (c[0] >= 1&&c[c[0]]==0) {
        c[0]--;
    }
}
int main() {
    int flag = 0;
    cin >> sa;
    a[0] = strlen(sa);
    for (int i = 1; i <= a[0]; i++) {
        a[i] = sa[i-1]-'0';
    }
    int yushu=Chufa13(a, c);
    Reverse(c);
    DeleteZero(c);
    for (int i = c[0]; i >= 1;i--) {
        cout << c[i];
    }
    cout << endl;
    cout << yushu;
    return 0;
}
  • 21
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值