• 【算法之路】高精度算法(实现加减乘除)


    目录

    一、高精度概念

    二、高精度算法的实现

    1、高精度加法(大整数相加)

    2、高精度减法(大整数减法)

    3、高精度乘法(大整数*小整数)

    4、高精度除法(大整数/小整数)


    一、高精度概念

    高精度算法,是一种处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几百亿的大数字。一般这类数字统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除,乘方,阶乘等运算。对于非常庞大的数字无法在计算机中正常存储。于是,将这个数字拆开成一位一位的,或者是四位四位的存储到一个数组中, 用一个数组去表示一个数字,这样这个数字就被称为是高精度数

    高精度就是说参与运算的数据和运算结果的范围,超出标准数据类型能表示的数据大小范围的运算。此时如果要得到正确的计算结果,就不能依靠普通方法实现了,而要在普通运算原理的基础上,加以辅助算法来实现超大数据的计算。
    例如:求两个 500 位的数据相乘的结果,这时就要用到高精度算法了。


    二、高精度算法的实现

    1、高精度加法(大整数相加)

    大整数又称为高精度整数,其含义就是用基本数据类型无法存储其精度的整数。 大整数的存储使用数组即可。

     

    思路:

    先将大整数倒序存储,然后从左往右相加,这样才算是从低位往高位加,并判断是否有进位,加出来的数取余后尾插到要保存的vector中,这样求出来的数还是逆序的,但是主函数会从后往前读

     AC代码:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //1、高精度加法(大整数加法)
    6. vector<int> add(vector<int>& A, vector<int>& B)
    7. {
    8. //如果B更大,因为下面代码都是以第一个形参作为for结束条件,所以要让大的是第一个形参
    9. if (A.size() < B.size()) return add(B, A);
    10. vector<int> C;
    11. int t = 0; //用来判断是否进位
    12. //注意这里是逆序的数从前往后加的
    13. for (int i = 0; i < A.size(); ++i)
    14. {//for循环是以大的数来作为循环结束条件的
    15. t += A[i];//for循环以A为结束条件,这里不用格外判断
    16. if (i < B.size()) t += B[i];//因没以B为结束条件,故这里要格外判断是否可以加
    17. C.push_back(t % 10);//加出来的数要的是余数
    18. t /= 10; //判断是否有进位
    19. }
    20. if (t) C.push_back(t);//有可能最后加完还有进位
    21. //第二种写法
    22. //这种写法不用格外判断最后是否有进位
    23. //for (int i = 0, t = 0; i < A.size()||t; ++i)
    24. //{
    25. // if (i < A.size()) t += A[i];//因为有t作为条件,故这里要格外判断
    26. // if (i < B.size()) t += B[i];//因没以B为结束条件,故这里要格外判断是否可以加
    27. // C.push_back(t % 10);//加出来的数要的是余数
    28. // t /= 10; //判断是否有进位
    29. //}
    30. return C;
    31. }
    32. int main()
    33. {
    34. string a, b;
    35. cin >> a >> b;
    36. vector<int> A, B;
    37. //把字符串逆序存入vector中,方便后续计算
    38. for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
    39. for (int i = b.size() - 1; i >= 0; --i) B.push_back(b[i] - '0');
    40. auto C = add(A, B);
    41. for (int i = C.size() - 1; i >= 0; --i) cout << C[i];
    42. cout << endl;
    43. return 0;
    44. }

    2、高精度减法(大整数减法)

    思路:

    和加法区别在于其一,减法是要借位而不是进位,其二,减法会导致有前导0存在。

    什么是前导0?比如124-113,我们存的是421,311,相减时是4-3=1,2-1=1,1-1=0,然后尾插导致C为110,我们最后是逆着读的,即011,(但正常124-113=11),这里011肯定不对,多了一个前导0,故我们最后要把这个前导0去掉变成11,然后逆着读出来就对了

    AC代码: 

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. //比较哪个数大,注意这里的数是从倒序存的,故后面的才是高位
    6. bool cmp(vector<int>& A, vector<int>& B)
    7. {
    8. if (A.size() != B.size()) return A.size() > B.size();
    9. for (int i = A.size() - 1; i >= 0; --i)
    10. if (A[i] != B[i])
    11. return A[i] > B[i];//不等从高位开始比
    12. return true;//相等
    13. }
    14. vector<int> sub(vector<int>& A, vector<int>& B)
    15. {//利用cmp函数比较,使大的数一定是A,与for循环代码相符
    16. vector<int> C;
    17. int t = 0;//判断借位
    18. for (int i = 0; i < A.size(); ++i)
    19. {
    20. t = A[i] - t;//每次都会减掉借位
    21. if (i < B.size()) t -= B[i];
    22. //关于(t+10)%10(t是减出来的数)
    23. //t若为正数(但<=9)其=t%10+10%10=t
    24. //t若为负数,正好可以借位+10然后取余数即可
    25. C.push_back((t + 10) % 10);
    26. if (t >= 0) t = 0;
    27. else t = 1; //<0肯定有借位了
    28. }
    29. //因为两个数相减会导致有多余的0出现,故去除前导0
    30. //size()>1是因为可能真的相减出现0,这种0不算前导0
    31. while (C.size() > 1 && C.back() == 0) C.pop_back();
    32. return C;
    33. }
    34. int main()
    35. {
    36. string a, b;
    37. cin >> a >> b;
    38. vector<int> A, B;
    39. //把字符串逆序存入vector中,方便后续计算
    40. for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
    41. for (int i = b.size() - 1; i >= 0; --i) B.push_back(b[i] - '0');
    42. vector<int> C;
    43. if (cmp(A, B)) C = sub(A, B); //正数
    44. else cout << "-", C = sub(B, A); //负数
    45. for (int i = C.size() - 1; i >= 0; --i) cout << C[i];
    46. cout << endl;
    47. return 0;
    48. }

    3、高精度乘法(大整数*小整数)

    思路: 

    AC代码: 

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. vector<int> mul(vector<int>& A, int b)
    6. {
    7. vector<int> C;
    8. for (int i = 0, t = 0; i < A.size() || t; ++i)
    9. {
    10. if (i < A.size()) t += A[i] * b;//加上t是因为上一次可能有乘出来的进位
    11. C.push_back(t % 10);
    12. t /= 10;//计算进位
    13. }
    14. //当b是0时,会出现前导0
    15. while (C.size() > 1 && C.back() == 0) C.pop_back();
    16. return C;
    17. }
    18. int main()
    19. {
    20. string a;
    21. int b;
    22. cin >> a >> b;
    23. vector<int> A;
    24. for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
    25. auto C = mul(A, b);
    26. for (int i = C.size() - 1; i >= 0; --i) cout << C[i];
    27. cout << endl;
    28. return 0;
    29. }

    4、高精度除法(大整数/小整数)

    思路:

     

    AC代码:

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. vector<int> div(vector<int>& A, int b, int& r)
    7. {
    8. vector<int> C;
    9. for (int i = A.size() - 1; i >= 0; --i)
    10. {
    11. r = r * 10 + A[i];
    12. C.push_back(r / b);
    13. r %= b; //计算余数
    14. }
    15. //逆置:因为我们是正常求,但最后是倒着读的,且便于去除前导0
    16. reverse(C.begin(), C.end());
    17. while (C.size() > 1 && C.back() == 0) C.pop_back();
    18. return C;
    19. }
    20. int main()
    21. {
    22. string a;
    23. int b;
    24. cin >> a >> b;
    25. vector<int> A;
    26. for (int i = a.size() - 1; i >= 0; --i) A.push_back(a[i] - '0');
    27. int r = 0; //余数
    28. auto C = div(A, b, r);
    29. for (int i = C.size() - 1; i >= 0; --i) cout << C[i];
    30. cout << endl << r << endl;
    31. return 0;
    32. }

  • 相关阅读:
    4.django-模板
    Vue3中通过 input 标签 发送文件/图片给后端
    一键帮您解决win11最新版画图工具难用问题!
    瑞吉外卖07-对于分类信息的CRUD
    linux————zabbix搭建
    Kubernetes架构提供哪些功能
    干货 | 携程火车票iOS项目开发体验优化实践
    封装,继承,java,220813,,
    【深度学习】可交互讲解图神经网络GNN
    基于探针的分布式追踪工具
  • 原文地址:https://blog.csdn.net/m0_74044018/article/details/134538246