高精度算法——加更

1、高精度算法是什么


在c++中int、long long int等存储方式只能计算十几位的整数运算,而当我们想要计算更多位时,就需要用到高精度算法。
高精度算法:它是处理大数字的数学计算方法,在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除等运算。
思想:

将这种大数字拆开,拆成一位一位的,这样可已输入位数很长的数,接下来将每一位取出,存入数组中 ,然后用一个数组去存储每个数字,最后再将数组进行相应的运算(加、减、乘、除、等)。


2、高精度运算易错点


高精度加法:

倒叙输入,倒序输出,但中间是正着运算;
相加之后的进位处理;
高精度减法:

考虑结果出现的正情况;
前导0的处理;
考虑减法的借位处理;
高精度乘法:

前导0的处理(0被相乘)!!!***容易被忽略***;
可以将乘法单个位数相乘再转化成加法的思想;
此时题目中没有涉及到负数的情况。如出现负数,只需考虑两个字符串第一位是否为负号,然后结尾特殊判断一下即可;
高精度除法:(高精度÷低精度)

输入、计算、输出、需要同时逆序或同时正序;
前导0的处理!!!***容易被忽略***;
不能考虑进位的情况!!


3、高精度加法


题目描述

给定两个正整数(不含前导 0),计算它们的和。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的和。

数据范围

1≤整数长度≤100000;

输入样例:

12
23
输出样例:

35
手动模拟——例如计算:567 + 28 = 595
先个位相加: 7 + 8 = 15,所以结果的个位是5,向十位进 1
再十位相加: 6 + 2 + 1(进位)= 9, 所以十位是 9,向百位进 0
在百位相加: 5 + 0 = 5, 所以结果的百位是 5
综上所述,计算结果为 595。
易错点:

一定要将数字进行倒叙输入,最后结果也是倒序输出,而中间的运算是正序运算。
s1,s2两个字符串下标是从0开始的。

#include<iostream>
#include<algorithm>
 
using namespace std;
const int N = 1e5 + 10;
 
string s1, s2;
int a[N], b[N], c[N];
 
int main()
{
    cin >> s1 >> s2;
    int j = 1, k = 1;//a、b数组的下标都是从1开始的
    for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
    for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';
 
    int ma = max(s1.size(), s2.size());//记录最大长度
    int ans = 0;
    for (int i = 1; i <= ma; i++)
    {
        ans = ans + (a[i] + b[i]);
        c[i] = ans % 10;
        ans = ans / 10;
    }
 
    if (ans) c[++ma] = ans;//**一定要注意最后是否会向前进一
    for (int i = ma; i >= 1; i--)
    {
        cout << c[i];
    }
    return 0;
}

4、高精度减法


题目描述:

给定两个正整数(不含前导 0),计算它们的差,计算结果可能为负数。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的差。

数据范围

1≤整数长度≤100000

输入样例:

32
11
输出样例:

21
易错点:

减法的借位处理

相减为负数的处理

前导0的处理!!!!****容易被忽略ke'yi****

#include<iostream>
#include<algorithm>
 
using namespace std;
const int N = 1e5 + 10;
 
string s1, s2;
int a[N], b[N], c[N], flag = 0;
 
int main()
{
    cin >> s1 >> s2;
    if (s1.size() < s2.size() || s1.size() == s2.size() && atoi(s1.c_str()) < atoi(s2.c_str()))
    //这个判断是用来s1和s2那个字符串更大的。atoi(s1.c_str())—将s1字符串转化成数字进行比较
    {
        flag = 1;
        swap(s1, s2);//保证s1始终是最大的字符串,同时做出正负的判断。
    }
    int j = 1, k = 1;//a,b下标从1开始
    for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
    for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';
 
    int ma = max(s1.size(), s2.size());//ma用来存最大长度的字符串个数
    for (int i = 1; i <= ma; i++)
    {
        if (a[i] - b[i] < 0)//错位相减
        {
            a[i] = a[i] + 10;
            a[i + 1] = a[i + 1] - 1;
        }
        c[i] = a[i] - b[i];
    }
    while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
    if (flag == 1) printf("-");//负数的判断
    for (int i = ma; i >= 1; i--)//
    {
        cout << c[i];
    }
    return 0;
}

5、高精度乘法


1、两个高精度整数相乘


题目描述

给定两个非负整数(不含前导 0) A 和 B,请你计算 A×B 的值。

输入格式

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式

共一行,包含 A×B 的值。

数据范围

1≤A的长度≤100000
0≤B≤10000;

输入样例:

2
3
输出样例:

6
易错点:

前导0的处理(0被相乘)!!!***容易被忽略***;
可以将乘法单个位数相乘再转化成加法的思想;
此时题目中没有涉及到负数的情况,如出现负数,只需考虑两个字符串第一位是否为负号,然后结尾特殊判断一下即可。

#include<iostream>
#include<algorithm>
 
using namespace std;
const int N = 1e6 + 10;
 
string s1, s2;
int a[N], b[N], s[N], c[N];
 
int main()
{
    cin >> s1 >> s2;
    int j = 1, k = 1;
    for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
    for (int i = s2.size() - 1; i >= 0; i--) b[k++] = s2[i] - '0';
 
    for (int i = 1; i <= s1.size(); i++)
    {
        for (int j = 1; j <= s2.size(); j++)
        {
            s[i + j - 1] += a[i] * b[j];//单个数组逐一相乘
        }
    }
    int ma = s1.size() + s2.size() - 1;//记录一下最高位数
    int ans = 0;
    for (int i = 1; i <= ma; i++)//高精度算法的核心
    {
        ans = ans + s[i];
        c[i] = ans % 10;
        ans = ans / 10;
    }
    if (ans) c[++ma] = ans;//考虑进位的情况
    while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
    for (int i = ma; i >= 1; i--)
    {
        cout << c[i];
    }
    return 0;
}

2、阶乘 —(n个低精度整数相乘,最终结果是高精度整数) 


题目描述:

输入一个正整数 N,输出 N 的阶乘。

输入格式
输入包含多组测试数据。

每组数据占一行,包含一个整数 N。

输出格式
每组数据输出占一行,输出 N 的阶乘。

数据范围
1≤N≤1000,
每个输入最多包含 100 组数据

输入样例:
 

4
5
15

输出样例:
 

24
120
1307674368000

#include<iostream>
#include<algorithm>
#include<cstring>
 
using namespace std;
 
const int N = 1e6 + 10;
int n, a[N], ans, x, m, d;
 
int main()
{
    while (cin >> n)
    {
        a[0] = 1, d = 1;
        for (int i = 1; i <= n; i++)//从1开始一直乘到本数;
        {
            x = 0;
            for (int j = 0; j < d; j++)//几位就循环几次
            {
                ans = a[j] * i + x;//每一位乘上i,加上余数后所得的数
                a[j] = ans % 10;//把最后一位给数组,其他的向前进
                x = ans / 10;//把ans的最后一位数去掉
            }
            while (x != 0)//用while把c分配到各个高位
            {
                a[d++] = x % 10;//每进一位位数加一
                x = x / 10;
            }
        }
 
        for (int i = d - 1; i >= 0; i--)
        {
            cout << a[i];//存放从后向前存放,输出就要倒叙输出
        }
        cout << endl;
    }
    return 0;
}

3、 Hanoi双塔问题——2*(pow(2,n)-1)——暴力的话会爆内存


题目描述

给定 A,B,C 三根足够长的细柱,在 A 柱上放有 2n 个中间有空的圆盘,共有 n 个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为 n=3 的情形)。


现要将这些圆盘移到 C 柱上,在移动过程中可放在 B 柱上暂存。要求:

每次只能移动一个圆盘;
A、B、C 三根细柱上的圆盘都要保持上小下大的顺序;
任务:设 An 为 2n 个圆盘完成上述任务所需的最少移动次数,对于输入的 n,输出 An。

输入格式
输入文件为一个正整数 n,表示在 A 柱上放有 2n 个圆盘。

输出格式
输出文件仅一行,包含一个正整数,为完成上述任务所需的最少移动次数 An。

数据范围
1≤n≤200


输入样例:

2

输出样例:
 

6
 思路:双塔问题所求的结果是单塔问题的2倍,即res=2*(pow(2,n)-1)=pow(2,n+1)-2;

#include<iostream>
#include<algorithm>
#include<cstring>
 
using namespace std;
 
const int N = 1e6 + 10;
int n, a[N], d, y = 2;
 
int main()
{
    while (cin >> n)
    {
        d = 1, a[0] = 1;
        for (int i = 1; i <= n + 1; i++)
        {
            int x = 0;
            for (int j = 0; j < d; j++)
            {
                int ans = a[j] * y + x;
                a[j] = ans % 10;
                x = ans / 10;
            }
            while (x != 0)
            {
                a[d++] = x % 10;
                x = x / 10;
            }
        }
        a[0] -= 2;//进行减2的操作(2的n次方尾数一定大于等于2)
        for (int i = d - 1; i >= 0; i--)
        {
            cout << a[i];
        }
        cout << endl;
    }
    return 0;
}

6、高精度除法


题目描述:

给定两个非负整数(不含前导 0) A,B,请你计算 A/B 的商和余数。

输入格式

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式

共两行,第一行输出所求的商,第二行输出所求余数。

数据范围

1≤A的长度≤100000,
1≤B≤10000,
B 一定不为 0!!

输入样例:

7
2
输出样例:

3
1
1、高精度÷低精度

#include<iostream>
#include<algorithm>
 
using namespace std;
const int N = 1e6 + 10;
 
string s1;
int a[N], x, c[N];
 
int main()
{
    cin >> s1 >> x;//x为低精度
    int j = 1;
    for (int i = s1.size() - 1; i >= 0; i--) a[j++] = s1[i] - '0';
 
    int ma = s1.size(), ans = 0;
    for (int i = ma; i >= 1; i--)//除法的核心运算
    {
        ans = ans * 10 + a[i];//上一位数*10加到下一位
        c[i] = ans / x;
        ans = ans % x;
    }
 
    while (c[ma] == 0 && ma > 1) ma--;//前导0的处理
    for (int i = ma; i >= 1; i--)
    {
        cout << c[i];
    }
    cout << endl << ans;//余数的输出
    return 0;
}


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/qq_64162685/article/details/128066736

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值