• 8-高精度计算(加法)


    我们知道,在C语言和C++中对于所能存储的数值的最大值是有明确的上限的。但是我们有时候会需要去计算一些数值比较大的数字:例如位数为1000、10000的数字的加减运算,这时候我们就需要使用新的运算方法了。

    这里引入高精度的大数据计算,它可以用计算位数很大例如10^{6}的数字。它的主要思想是利用数组进行存储大数的位数,并且利用计算规则的特点来进行计算,下面我们来看看加法。

    首先是大数据的处理过程,我们一般long类型变量如果存不下的数据,我们考虑用一个数组或者vector类型的容器来存储。例如数字1598,我们可以用一个数组将其倒过来存储,arr[0]先存储个位,然后后面位数依次存进去(如下图下方图)。这样存有个好处,因为我们做加法运算时有可能会最大位向前进一位,如果此时我们选择arr[0]为最大位,那么我们进一就需要将整个数组向后镦一位(如下图上方图)。

    了解完存储大数字的方式,接下来我们先来回忆一下加法的运算过程:例如我们有两个数组A,B,C,它们存储大数a,b的每个位上的数据,C为存储结果各个位数值的数组。然后我们先从两个数组对应的个位算起,将个位数字计算完后,看其是否需要向十位进位,以此类推计算。因为还要考虑进位问题,所以我们索性定义C每一位都是(A[i]+B[i]+t)%10,这里的t是前一位向本位进的位数。个位是t就是0就可以。例如下面的式子:A={9,3,1},B={7,3}。C[0]=(A[0]+B[0]+0)%10=16%10=6;C[1]=(A[1]+B[1]+1)%10=7%10=7;C[2]=(A[2]+0)%10=1%10=1。所以C为{6,7,1}。

    按照这个思路,我们可以写出大数加法的代码,这里为了方便使用了容器vector:

    整体代码分为两段:第一段是处理数据,第二段是大数计算。

    先来看处理数据:我们用的是string类型的变量接收数据,所以我们要想换成vector容器存储每一个位,就需要将字符串中每一个数字转换为一个int类型的数据存进去A/B容器中。数字字符和数字有一个对应关系:x(char类型)-'0' = x(int类型)。这样就能获得一个存储着大数据a和b的容器了。

    1. for (int i = a.size()-1; i >= 0; i--) A.push_back(a[i] - '0');
    2. for (int i = b.size()-1; i >= 0; i--) B.push_back(b[i] - '0');

    接下来就是核心的大数计算的部分了:

    我们将两个需要进行加运算的容器传进函数中,然后用一个循环将两容器的每一位相加。举个例子:两个数字相加:120和3,它们结果是123,这里的120中的1和2没有运算,因为3只需和120中的个位运算。同理,两个数相加要么是两个数刚好相等,或者一方比另一方位数高,此时加法停止的条件就是位数高的那个数字的最高位计算完毕。所以循环的结束条件是当加到A、B中最大的那位,此时加法停止。所以有下面的停止判断条件。

     i < A.size() || i < B.size()

     然后我们来看里面的两个if,这两个if是我们不确定A还是B的位数高,所以让位数低的位数计算完后先停止运算,而位数高的继续计算。然后将加得的数据对十取模来获得A、B对应位的结果,赋给C,最后再将t除10获得进位。最后的if(t)是判断两个数相加是否需要增位,判断最后运算完是否需要向下一次进1,也就是判断t是否为1。是就加1,不是不处理。

    1. vector<int> add(vector<int>& A, vector<int>& B)
    2. {
    3. vector<int> C;
    4. int t = 0;
    5. for (int i = 0; i < A.size() || i < B.size(); i++)
    6. {
    7. if (isize())t += A[i];
    8. if (isize())t += B[i];
    9. C.push_back(t % 10);
    10. t = t / 10;
    11. }
    12. if (t) C.push_back(1);
    13. return C;
    14. }

    总体代码: 

    1. #include
    2. using namespace std;
    3. #include
    4. vector<int> add(vector<int>& A, vector<int>& B)
    5. {
    6. vector<int> C;
    7. int t = 0;
    8. for (int i = 0; i < A.size() || i < B.size(); i++)
    9. {
    10. if (isize())t += A[i];
    11. if (isize())t += B[i];
    12. C.push_back(t % 10);
    13. t = t / 10;
    14. }
    15. if (t) C.push_back(1);
    16. return C;
    17. }
    18. int main()
    19. {
    20. string a, b;
    21. vector<int> A, B;
    22. cin >> a >> b;
    23. for (int i = a.size()-1; i >= 0; i--) A.push_back(a[i] - '0');
    24. for (int i = b.size()-1; i >= 0; i--) B.push_back(b[i] - '0');
    25. auto C = add(A, B);
    26. for (int i = C.size()-1; i >= 0; i--) cout << C[i];
    27. return 0;
    28. }

  • 相关阅读:
    ICCV 2023 | MPI-Flow:从单视角构建的多平面图像中学习光流
    通达信程序化接口能为投资解决哪些问题?
    iOS开发Swift-5-自动布局AutoLayout-摇骰子App
    振南技术干货集:C语言的一些“骚操作”及其深层理解(4)
    释放数据价值的真正法宝,数据要素市场化开发迫在眉睫
    设置centos系统语言设置为中文
    【小黑送书—第四期】>>用“价值”的视角来看安全:《构建新型网络形态下的网络空间安全体系》
    数组复制之System.arraycopy
    第 12 章 栈与队列
    常用的表单校验规则——邮箱/QQ/身份证号码/微信/电话/数字字母/整数/文本/密码等
  • 原文地址:https://blog.csdn.net/m0_61151031/article/details/127600669