C/C++实现高精度四则运算

什么是高精度?

高精度算法High Accuracy Algorithm)是处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数。(摘自百度百科

为什么要用高精度算法?

在C/C++中,我们经常会碰到限定数据范围的情况。

C++标准规定:

int占一个机器字长。在32位系统中int占32位,也就是4个字节,所以int的范围是[-2^31,2^31-1],

为10^9数量级;

long long的范围是[-2^63,2^63-1],为10^18数量级。那么如果我们需要计算10^100该怎么办?

高精度加法

a2 a1
b2 b1
c2 c1

c1 = a1 + b1,c2 = a2 + b2.但是我们还有一个进位的问题。

这里我们以 68 + 25 = 93 为例。

a1 = 8,b1 = 5,c1 = 13;a2 = 6,b2 = 2,c2 = 8。此时我们利用一个累加的办法:

c[ i ] += a[ i ] + b[ i ];即可在每一次进行加法的时候将低位的进位加上来。

        crr[i] += arr[i] + brr[i]; // 累加是因为后一步才计算的进位
        crr[i + 1] = crr[i] / 10;
        crr[i] = crr[i] % 10;

或许已经有小伙伴发现,我们的字符串下标是0~n,为什么我的是n~0?

因为0~n不符合我们平时计算的习惯,所以我们将第一个数和最后一个数调换,第二数和倒数第二个数调换,以此类推。

到此,我们还有最后一个问题,就是处理多余的0。我们一开始给数组全部赋值为0,假设我们设置数组长度为3,那么我们68 + 25 计算出来的结果就是093,所以我们需要删除前面的0。

    if (crr[len_c] == 0 && len_c > 0) // 删除前面的0
    {
        len_c--;
    }

那么为什么lc要大于0呢,假设我们仅仅计算0+0,最后的结果就是0,这里不能删除!

源代码

#include 
#include 
#include 
#include 
using namespace std;
char str1[505], str2[505];
int arr[505], brr[505], crr[505];
int main()
{
    int len_a, len_b, len_c;
    scanf("%s", str1);
    scanf("%s", str2);

    len_a = strlen(str1);
    len_b = strlen(str2);

    for (int i = 0; i < len_a; i++)
    {
        arr[len_a - i] = str1[i] - '0'; // 将字符转化成数字(ASCII值计算),并且将字符逆序计算
    }
    for (int i = 0; i < len_b; i++)
    {
        brr[len_b - i] = str2[i] - '0';
    }

    len_c = max(len_a, len_b) + 1;
    for (int i = 1; i < len_c; i++)
    {
        crr[i] += arr[i] + brr[i]; // 累加是因为后一步才计算的进位
        crr[i + 1] = crr[i] / 10;
        crr[i] = crr[i] % 10;
    }

    if (crr[len_c] == 0 && len_c > 0) // 删除前面的0
    {
        len_c--;
    }
    for (int i = len_c; i > 0; i--)
    {
        printf("%d",crr[i]);
    }
    return 0;
}

高精度减法

高精度减法与高精度加法在基本操作上都相同,我们同样利用字符数组存储数据,然后模拟减法运算法则。

要点 

我们现在求解A - B,假设A = 2383,B = 8371.

1.如果A < B,则需要交换A与B。

        因为用一个大的数减去一个小的数,比较容易计算,只要在结果上加一个负号即可。

        A - B = -(B - A)= - (5988)

2.如果a[ i ] < b[ i ],需要向高位借一当十使用

        if(arr[i] < brr[i]){
            arr[i + 1]--;//向高位借一
            arr[i]+=10;//高位借一当做十使用
        }
        crr[i] = arr[i] - brr[i];

源代码

#include 
#include 
#include 
#include 
using namespace std;
char str1[10086], str2[10086], str3[10086];
int arr[10086], brr[10086], crr[10086];
int flag = 0;
bool compare(char str1[], char str2[]) // 比较两个数的大小
{
    int u = strlen(str1), v = strlen(str2);
    if (u != v)
        return u > v;
    for(int i = 0;i < u;i++){
        if(str1[i] != str2[i])
            return str1[i] > str2[i];
    }
    return true;
}

int main(){
    int len_a,len_b,len_c;
    scanf("%s",str1);
    scanf("%s",str2);
    if(!compare(str1,str2)){ //s1 < s2 ,交换 s1 和 s2 的值
        flag = 1;
        strcpy(str3,str1);
        strcpy(str1,str2);
        strcpy(str2,str3);
    }
    len_a = strlen(str1);
    len_b = strlen(str2);
    for(int i = 0;i < len_a;i ++){
        arr[len_a - i] = str1[i] - '0';
    }
    for(int i = 0;i < len_b;i ++){
        brr[len_b - i] = str2[i] - '0';
    }
    len_c = max(len_a,len_b);
    for(int i = 1;i <= len_c;i++){
        if(arr[i] < brr[i]){
            arr[i + 1]--;
            arr[i]+=10;
        }
        crr[i] = arr[i] - brr[i];
    }
    while(crr[len_c] == 0 && len_c > 1)
        len_c--;
    if(flag == 1)
        printf("-");
        for(int i = len_c;i > 0;i --){
            printf("%d",crr[i]);
        }
    return 0;
}

高精度乘法

高精度乘法和高精度加法异曲同工。我们对乘法的运算法则进行模拟。与加法不同的事,我们需要用到双重循环。

图示

C/C++实现高精度四则运算_第1张图片

 核心算法

    for (int i = 1; i <= len_a; i++) 
    {
        for (int j = 1; j <= len_b; j++)
        {
            crr[i + j - 1] += arr[i] * brr[j]; // ①
            crr[i + j] += crr[i + j - 1] / 10; // ②
            crr[i + j - 1] %= 10;
        }
    }

① 对每项进行累加

② 如果累加的值超过了10,则向前进位

同时,与加减法不同的是,如果我们计算1000 * 0,结果会出现多个0,而加减法中最多有一个前导0,所以我们要利用循环,多次删除前导0。同样,如果有且只有一个0,则保留。

    for (int i = 1; i <= len; i++)
    {
        if (crr[len_c] == 0 && len_c > 0)
        {
            len_c--;
            if (len_c == 1)
                break;
        }
    }

完整代码

#include 
#include 
#include 
#include 
using namespace std;
char str1[10001], str2[10001];
int arr[10001], brr[10001], crr[10001];
int main()
{
    int len_a, len_b, len_c;
    scanf("%s", str1);
    scanf("%s", str2);

    len_a = strlen(str1);
    len_b = strlen(str2);

    for (int i = 0; i < len_a; i++)
    {
        arr[len_a - i] = str1[i] - '0';
    }
    for (int i = 0; i < len_b; i++)
    {
        brr[len_b - i] = str2[i] - '0';
    }

    len_c = len_a + len_b;           // 结果的长度最多等于两个数的长度之和(比如4位数×3位数,        
                                                                     //结果最多也就是7位数)
    for (int i = 1; i <= len_a; i++) 
    {
        for (int j = 1; j <= len_b; j++)
        {
            crr[i + j - 1] += arr[i] * brr[j];
            crr[i + j] += crr[i + j - 1] / 10;
            crr[i + j - 1] %= 10;
        }
    }

    int len = len_c;
    for (int i = 1; i <= len; i++)
    {
        if (crr[len_c] == 0 && len_c > 0)
        {
            len_c--;
            if (len_c == 1)
                break;
        }
    }
    for (int i = len_c; i > 0; i--)
    {
        printf("%d", crr[i]);
    }
    return 0;
}

高精度除法

注:这里我们仅仅解析高精度除以低精度。(高精度除以高精度后续会推出)

除法的运算法则就是将被除数的每一位分别除数相除,不够就取0的方法。

规律:我们将每一位相除之后的余数乘以10再加下一位数的和作为下一次运算的被除数。

图示

C/C++实现高精度四则运算_第2张图片

 核心算法

    for (int i = 1; i <= len_a; ++i)// i从1开始到len_a,表示商最多有len_a位
    {
        crr[i] = (x * 10 + arr[i]) / b;
        x = (x * 10 + arr[i]) % b;
    }

完整代码

#include 
#include 
using namespace std;
char str[5005];
long long b, arr[5005], crr[5005], x, len_a, len_c;
int main()
{
    cin >> str >> b;
    len_a = strlen(str);
    for (int i = 1; i <= len_a; i++)// 将被除数逐位放进数组
        arr[i] = str[i - 1] - '0';
    for (int i = 1; i <= len_a; ++i)// i从1开始到len_a,表示商最多有len_a位
    {
        crr[i] = (x * 10 + arr[i]) / b;
        x = (x * 10 + arr[i]) % b;
    }
    len_c = 1;
    while (crr[len_c] == 0 && len_c < len_a)// 循环删除前导0,同乘法类似
        len_c++;
    for (int i = len_c; i <= len_a; ++i)
        cout << crr[i];
    return 0;
}

总结:

高精度运算其实就是利用数组去模拟我们的运算法则,都是较为简单的算法。

注:本文参考视频高精度算法全套(加,减,乘,除,全网最详细)_哔哩哔哩_bilibili

对其进行了修饰和优化,如果有不太懂的地方,建议食用视频。

你可能感兴趣的:(c++,开发语言,c语言)