高精度专项 粗粗粗粗讲

咳咳,今天我来给大家,粗略的讲讲高精度的计算,说通俗点就是,用数组模拟精度,用字符串读入所谓的高精度数,然后把各各数位存int型数组里就ok了啦~

<1>高精度加法:

i ) 高精度大整数加法:

Description

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

Input

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

Output

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

Sample Input

22222222222222222222
33333333333333333333

Sample Output

55555555555555555555

思路:

就按照我刚才说的套路模拟一下~暴力特判一下谁的长度长,然后该进位就进位,不进位就直接加,注意数组下标的对应,显然是0难度啦~

不理解加法原理的,看一下这个链接 https://blog.csdn.net/ericgipsy/article/details/79942914

这是我不久前打的一场比赛,B题,奇怪的加法,是不进位加法,如果连不进位的你都看懂了,进位的就小case啦~

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
char s1[205], s2[205];
int a1[205], a2[205];
int ans[205];
int dis[205]; //记录当前位对下一位的进位

int main() {
    scanf("%s %s", s1, s2);
    int l1 = strlen(s1);
    int l2 = strlen(s2);
    for(int i = 0; i < l1; i++) a1[l1 - i] = s1[i] - '0';
    for(int i = 0; i < l2; i++) a2[l2 - i] = s2[i] - '0';
    memset(dis, 0, sizeof(dis));
    memset(ans, 0, sizeof(ans));
    if(l1 > l2) {
        for(int i = 1; i <= l2; i++) {
            ans[i] = (a1[i] + a2[i] + dis[i - 1]) % 10;
            dis[i] = (a1[i] + a2[i] + dis[i - 1]) / 10;
        }
        for(int i = l2 + 1; i <= l1; i++) ans[i] = a1[i] + dis[i - 1];
        for(int i = l1; i >= 1; i--) printf("%d", ans[i]);
        printf("\n");
    }
    else if(l2 > l1) {
        for(int i = 1; i <= l1; i++) {
            ans[i] = (a1[i] + a2[i] + dis[i - 1]) % 10;
            dis[i] = (a1[i] + a2[i] + dis[i - 1]) / 10;
        }
        for(int i = l1 + 1; i <= l2; i++) ans[i] = a2[i] + dis[i - 1];
        for(int i = l2; i >= 1; i--) printf("%d", ans[i]);
        printf("\n");
    }
    else {
        for(int i = 1; i <= l1; i++) {
            ans[i] = (a1[i] + a2[i] + dis[i - 1]) % 10;
            dis[i] = (a1[i] + a2[i] + dis[i - 1]) / 10;
        }
        if(dis[l1] == 1) printf("1");
        for(int i = l1; i >= 1; i--) printf("%d", ans[i]);
        printf("\n");
    }

}

ii ) 高精度浮点型加法:

Description

求2个浮点数相加的和。
题目中输入输出中出现浮点数都有如下的形式:
P1P2...Pi.Q1Q2...Qj
对于整数部分,P1P2...Pi是一个非负整数。
对于小数部分,Qj不等于0。

Input

第1行是测试数据的组数n,每组测试数据占2行,分别是两个加数。每组测试数据之间有一个空行,每行数据不超过100个字符。

Output

n行,每组测试数据有一行输出是相应的和。由输入保证输出一定是一个小数部分不为0的浮点数,即由输入保证输出结果至少有一位小数。

Sample Input

2
0.111111111111111111111111111111
0.111111111111111111111111111111

10000000.655555555555555555555555555555
1.444444444444444444444444444445

Sample Output

0.222222222222222222222222222222
10000002.1

思路:和上面那个区别不大,就分别对整数部分和小数部分进行两个方向的进位加法就可以啦,注意小数最高位进位要进到整数的最低位,因此,整数进位值的初始化要是小数最高位进位,详见代码注释。

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int cas;
char s1[105], s2[105];
int a1[105], a2[105]; //整数部分
int b1[105], b2[105]; //小数部分
int ans1[105], ans2[105]; //答案的整数和小数部分

int main() {
    scanf("%d", &cas);
    while(cas--) {
        scanf("%s %s", s1, s2);
        int l1 = strlen(s1), l2 = strlen(s2);

        memset(ans1, 0, sizeof(ans1));
        memset(ans2, 0, sizeof(ans2));
        memset(a1, 0, sizeof(a1));
        memset(a2, 0, sizeof(a2));
        memset(b1, 0, sizeof(b1));
        memset(b2, 0, sizeof(b2));

        int pos1, pos2;
        for(int i = 0; i < l1; i++) if(s1[i] == '.') pos1 = i;
        for(int i = 0; i < l2; i++) if(s2[i] == '.') pos2 = i;
        for(int i = 0; i < pos1; i++) a1[pos1 - i] = s1[i] - '0';
        for(int i = 0; i < pos2; i++) a2[pos2 - i] = s2[i] - '0';
        for(int i = pos1 + 1; i < l1; i++) b1[i - pos1] = s1[i] - '0';
        for(int i = pos2 + 1; i < l2; i++) b2[i - pos2] = s2[i] - '0';

        int ln1 = l1 - pos1, ln2 = l2 - pos2; //小数部分长度
        int t = 0; //小数进位
        if(ln1 > ln2) {
            for(int i = ln1; i > ln2; i--) ans2[i] = b1[i];
            for(int i = ln2; i >= 1; i--) {
                ans2[i] = (b1[i] + b2[i] + t) % 10;
                t = (b1[i] + b2[i] + t) / 10;
            }
        }
        else if(ln1 < ln2) {
            for(int i = ln2; i > ln1; i--) ans2[i] = b2[i];
            for(int i = ln1; i >= 1; i--) {
                ans2[i] = (b1[i] + b2[i] + t) % 10;
                t = (b1[i] + b2[i] + t) / 10;
            }
        }
        else {
            for(int i = ln2; i >= 1; i--) {
                ans2[i] = (b1[i] + b2[i] + t) % 10;
                t = (b1[i] + b2[i] + t) / 10;
            }
        }

        //for(int i = 1; i <= max(ln1, ln2) - 1; i++) printf("%d", ans2[i]);
        int pos;
        bool flg = 0;
        for(int i = max(ln1, ln2) - 1; i >= 1; i--) {
            if(ans2[i] != 0) {
                flg = 1;
                pos = i;
                break;
            }
        }

        int lnn1 = pos1, lnn2 = pos2; //整数部分长度
        int p = t; //整数进位, 初始化要等与小数最高位进位
        if(lnn1 > lnn2) {
            for(int i = 1; i <= lnn2; i++) {
                ans1[i] = (a1[i] + a2[i] + p) % 10;
                p = (a1[i] + a2[i] + p) / 10;
            }
            for(int i = lnn2 + 1; i <= lnn1; i++) {
                ans1[i] = (a1[i] + p) % 10;
                p = (a1[i] + p) / 10;
            }
        }
        else if(lnn1 < lnn2) {
            for(int i = 1; i <= lnn1; i++) {
                ans1[i] = (a1[i] + a2[i] + p) % 10;
                p = (a1[i] + a2[i] + p) / 10;
            }
            for(int i = lnn1 + 1; i <= lnn2; i++) {
                ans1[i] = (a2[i] + p) % 10;
                p = (a2[i] + p) / 10;
            }
        }
        else {
            for(int i = 1; i <= lnn1; i++) {
                ans1[i] = (a1[i] + a2[i] + p) % 10;
                p = (a1[i] + a2[i] + p) / 10;
            }
        }
        if(p == 1) printf("1");
        for(int i = max(lnn1, lnn2); i>= 1; i--) printf("%d", ans1[i]);
        if(flg) {
            printf(".");
            for(int i = 1; i <= pos; i++) printf("%d", ans2[i]);
        }
        printf("\n");
    }
    return 0;

}

<2>高精度乘法:

Description

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

Input

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

Output

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

Sample Input

12345678900
98765432100

Sample Output

1219326311126352690000

思路:手写一下乘法算式就能发现其中的规律了!!!一定要亲自手写一下!!!套路都是一样滴!!!

本人AC代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
char s1[205], s2[205];
int a1[205], a2[205];
int ans[1005];

int main() {
    char s1[1500], s2[1500];
    scanf("%s %s", s1, s2);
    int l1 = strlen(s1), l2 = strlen(s2);
    for(int i = 0; i < l1; i++) a1[i] = s1[l1 - 1 - i] - '0';
    for(int i = 0; i < l2; i++) a2[i] = s2[l2 - 1 - i] - '0';
    memset(ans, 0, sizeof(ans));
    for(int i = 0; i < l2; i++) {
        for(int j = 0; j < l1; j++) ans[i + j] += a1[j] * a2[i];
    }   
    for(int i = 0; i < l1 + l2; i++) {
        ans[i + 1] += ans[i] / 10;
        ans[i] %= 10;
    }
    int pos;
    for(pos = 1005; pos > 0; pos--) {
        if(ans[pos] != 0) break;
    }
    for(int i = pos; i >= 0; i--) printf("%d", ans[i]);
    printf("\n");
    return 0;

}

<3>高精度幂:

Description

任意给定一个正整数N(N≤100),计算2的N次方的值。

Input

输入只有一个正整数N。

Output

输出2的N次方的值。

Sample Input

5

Sample Output

32

思路:

之前ACM的一个大佬给我讲过,有个裸板子,其实最开始我也看不懂,但是你就顺着循环手推一下就明白了!举个栗子,2^n,在n == 4时,进行第一次进位变成了16,  然后再变成32,接着是64,再结合板子循环里的语句,自己认真想想,就会想通啦~

本人AC代码  -> 裸裸裸裸板子~ :

//A的n次方 高精度幂
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int A = 2;
int n;
int ans[1005];

int main() {
    scanf("%d", &n);
    int t = 0; //进位
    ans[99] = 1;
    while(n--) {
        int tmp = 99;
        while(tmp >= 0) {
            int p = ans[tmp] * A + t;
            ans[tmp] = p % 10;
            t = p / 10;
            tmp--;
        }
    }
    int pos;
    for(pos = 0; pos < 100; pos++) if(ans[pos] != 0) break;
    while(pos < 100) {
        printf("%d", ans[pos]);
        pos++;
    }
    printf("\n");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值