大数据的加法、减法、乘法以及阶乘的计算问题

本文介绍了一种使用字符数组处理大数加法、减法、乘法及阶乘的方法,解决了传统数据类型因长度限制而无法处理大数据计算的问题。通过具体的C语言实现案例,展示了如何进行大数计算并提供了一个简单的错误处理示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  限于数据类型的长度有限,对于大数据的计算就无能为力了,这里主要是采用字符数组解决精度问题。

  加法、减法的思路差不多,主要就是采用我们固有的思维来计算,直接一位一位地相加。减法的话,先

判断2个数的大小,让较大的数始终在前面,并且改变相应的数据长度,把结果放在一个临时的缓冲区里面。

计算完毕后,再把数据写入到用户的缓冲区中,并且除去前面多余的0。乘法的计算就有点不同了,最大的

不同之处就是在于我们自己算乘法的时候还要算加法,这里我把加法合到了算乘法的过程中,也免除了溢出的

危险,计算量也小些了,每一位乘之前取结果当前位的值保存起来,然后连带进位一起加起来,就避免了最后

算加法的问题。

  算阶乘的时候,主要就是确定该给临时缓冲区分配多大内存。最后大概算了下,一位数分配1*1个,两位数就分配2*1个,

三位数就分配3*1。专门写了个函数用于返回分配数量大小。分配3个这么大的缓冲区,一个存取当前每一次的计算结果(逆序表示),

第二个复制该结果(逆序表示),第三个存取待乘的数据(顺序表示)。还是乘法结束后,加法也完毕了,然后进入下一次乘法。

怎么想的就是怎么做的。用gcc编译的时候,注意带上-lm选项,链接math库,下边是一个带简单错误处理的demo以及源代码。

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <stdlib.h>  
  4. #include <math.h>  
  5. #include <assert.h>  
  6.   
  7. int ystrlen( const char* str )  
  8. {  
  9.     int len;  
  10.     assert( str != NULL );  
  11.     len = 0;  
  12.       
  13.     while( (*str--) !='\0' )   
  14.     {   
  15.         len++;   
  16.     }   
  17.     return len;  
  18. }  
  19.   
  20. int get_allocate_num(const int* num1, const int* num2)  
  21. {  
  22.     return (*num1 >= *num2) ? *num1+1 : *num2+1;  
  23. }  
  24.   
  25. void big_add(const char *num1, const char *num2, char *res)  
  26. {  
  27.     //res存储计算后的结果  
  28.     int len1 = strlen(num1);  
  29.     int len2 = strlen(num2);  
  30.     int i, j, k, num;  
  31.     char flag = 0;//进位标志  
  32.     char *temp_res, temp;//临时存取结果  
  33.   
  34.     num = get_allocate_num(&len1, &len2);  
  35.     temp_res = (char *)malloc(num);  
  36.   
  37.     i = len1 - 1;  
  38.     j = len2 - 1;  
  39.     for (k = num - 1; k >= 0; k--) {  
  40.         if (i >= 0 && j >= 0) {//加号两边都有数  
  41.             temp = num1[i--] + num2[j--] + flag;  
  42.             if (temp > 0x69) {//有进位  
  43.                 temp_res[k] = temp - 0x3a;  
  44.                 flag = 0x01;  
  45.             } else {  
  46.                 temp_res[k] = temp - 0x30;  
  47.                 flag = 0x0;  
  48.             }  
  49.         } else if (i >= 0 && j < 0) {//加号右边结束  
  50.             temp = num1[i--] + flag;  
  51.             if (temp > 0x39) {//有进位  
  52.                 temp_res[k] = 0x30;  
  53.                 flag = 0x01;  
  54.             } else {  
  55.                 temp_res[k] = temp;  
  56.                 flag = 0x0;  
  57.             }  
  58.         } else if (i < 0 && j >= 0) {//加号左边结束  
  59.             temp = num2[j--] + flag;  
  60.             if (temp > 0x39) {//有进位  
  61.                 temp_res[k] = 0x30;  
  62.                 flag = 0x01;  
  63.             } else {  
  64.                 temp_res[k] = temp;  
  65.                 flag = 0x0;  
  66.             }  
  67.         } else {//加号左边 右边刚结束  
  68.             temp = flag;  
  69.             if (temp) {//有无进位计算此次就结束  
  70.                 temp_res[0] = 0x31;  
  71.                 strncpy(res, temp_res, num);  
  72.                 res[num] = '\0';  
  73.             } else {//此时既无进位  
  74.                 strncpy(res, &temp_res[1], num-1);  
  75.                 res[num-1] = '\0';  
  76.             }  
  77.         }  
  78.     }  
  79.     free(temp_res);  
  80. }  
  81.   
  82. int big_cmp(const char *num1, const int *len1, const char *num2, const int *len2)   
  83. {  
  84.     int i;  
  85.   
  86.     if (*len1 > *len2) {//减数大  
  87.         return 1;  
  88.     } else if (*len1 < *len2) {//被减数大  
  89.         return -1;  
  90.     } else {  
  91.         for (i = 0; i < *len1; i++) {  
  92.             if (num1[i] > num2[i]) {  
  93.                 return 1;  
  94.             } else if (num1[i] < num2[i]) {  
  95.                 return -1;  
  96.             }  
  97.         }  
  98.         return 0;//2个数相等  
  99.     }  
  100. }  
  101.   
  102. void earse_zero(char *res, const int *num)  
  103. {//擦除多余的0  
  104.     int len;  
  105.     int i = 0;  
  106.     char *temp;  
  107.   
  108.     if (res[0] == '-') {  
  109.         i = 1;  
  110.         while (res[i] == 0x30) {  
  111.             i++;  
  112.         }  
  113.         if (i != 1) {  
  114.             len = *num - i + 1;  
  115.             temp = (char *)malloc(len);  
  116.             strncpy(temp, &res[i], len);  
  117.             strncpy(&res[1], temp, len);  
  118.             free(temp);  
  119.         }  
  120.     } else {  
  121.         while (res[i] == 0x30) {  
  122.             i++;  
  123.         }  
  124.         if (i != 0) {  
  125.             len = *num - i;  
  126.             temp = (char *)malloc(len);  
  127.             strncpy(temp, &res[i], len);  
  128.             strncpy(res, temp, len);  
  129.             free(temp);  
  130.         }  
  131.     }  
  132. }  
  133. void big_sub(const char *num1, const char *num2, char *res)  
  134. {  
  135.     //res存储计算后的结果  
  136.     int len1 = strlen(num1);  
  137.     int len2 = strlen(num2);  
  138.     int i, j, k, num;  
  139.     char flag = 0, flag_negetive = 0;//进位标志  
  140.     char *temp_res, temp;//临时存取结果  
  141.       
  142.     i = len1 - 1;  
  143.     j = len2 - 1;  
  144.     k = big_cmp(num1, &len1, num2, &len2);  
  145.     if (k == 0) {  
  146.         //相等  
  147.         res[0] = 0x30;  
  148.         res[1] = '\0';  
  149.     } else {  
  150.         //不等  
  151.         num = get_allocate_num(&len1, &len2);  
  152.         temp_res = (char *)malloc(num);  
  153.         if (k == -1) {//始终让num1指向较大数,同时也改变数据的长度  
  154.             k = (int)num1;  
  155.             num1 = num2;  
  156.             num2 = (const char *)k;  
  157.             k = i;  
  158.             i    = j;  
  159.             j    = k;  
  160.             flag_negetive = 1;  
  161.         }  
  162.         for (k = num - 1; k > 0; k--) {  
  163.             if (j >= 0) {  
  164.                 if (k == 1 && i == 0 && j == 0) {//位数相同  
  165.                     temp_res[1] = num1[0] - num2[0] - flag + 0x30;  
  166.                     if (flag_negetive == 1) {//结果为负数  
  167.                         strncpy(&res[1], &temp_res[1], num-1);  
  168.                         res[0] = '-';  
  169.                         res[num] = '\0';  
  170.                     } else {  
  171.                         strncpy(res, &temp_res[1], num-1);  
  172.                         res[num-1] = '\0';  
  173.                     }  
  174.                 } else {  
  175.                     temp = num1[i--] - num2[j--] - flag;  
  176.                     if (temp < 0x0) {//有借位  
  177.                         temp_res[k] = temp + 0x3a;  
  178.                         flag = 0x01;  
  179.                     } else {  
  180.                         temp_res[k] = temp + 0x30;  
  181.                         flag = 0x0;  
  182.                     }  
  183.                 }  
  184.             } else {  
  185.                 temp = num1[i--] - flag;  
  186.                 if (k == 1) {//最后一位  
  187.                     if (temp > 0x30) {  
  188.                         temp_res[1] = temp;  
  189.                         if (flag_negetive == 1) {//结果为负数  
  190.                             temp_res[0] = '-';//添加负号  
  191.                             strncpy(res, temp_res, num);  
  192.                             res[num] = '\0';  
  193.                         } else {  
  194.                             strncpy(res, &temp_res[1], num-1);  
  195.                             res[num-1] = '\0';  
  196.                         }  
  197.                     } else {//有借位  
  198.                         if (flag_negetive == 1) {//结果是负数  
  199.                             temp_res[1] = '-';  
  200.                             strncpy(res, &temp_res[1], num-1);  
  201.                             res[num-1] = '\0';  
  202.                         } else {  
  203.                             strncpy(res, &temp_res[2], num-2);  
  204.                             res[num-2] = '\0';  
  205.                         }  
  206.                     }  
  207.                 } else {  
  208.                     if (temp >= 0x30) {  
  209.                         temp_res[k] = temp;  
  210.                         flag = 0x0;  
  211.                     } else {//有借位  
  212.                         temp_res[k] = temp + 0xa;  
  213.                         flag = 0x01;  
  214.                     }  
  215.                 }  
  216.             }  
  217.         }  
  218.         free(temp_res);  
  219.         earse_zero(res, &num);  
  220.     }  
  221. }  
  222.   
  223. void big_mul(const char *num1, const char *num2, char *res)  
  224. {  
  225.     int len1 = strlen(num1);//num1为乘数  
  226.     int len2 = strlen(num2);  
  227.     int i, j, k;  
  228.     char *temp_res, temp, temp_mul, last_res;  
  229.     char flag = 0x0;  
  230.   
  231.     if (num1[0] == 0x30 || num2[0] == 0x30) {  
  232.         res[0] = 0x30;  
  233.         res[1] = '\0';  
  234.     } else {  
  235.         k = len1 + len2;  
  236.         temp_res = (char *)malloc(k);  
  237.         memset(temp_res, 0, k);  
  238.           
  239.         for (i = len2 - 1; i >= 0; i--) {  
  240.             k = len1 + i;  
  241.             for (j = len1 - 1; j >= 0; j--) {  
  242.                 //尽可能减少循环 每次的结果都是加了上次的结果 避免再把结果加起来  
  243.                 if (i == len2 - 1 || temp_res[k] == 0x0) {  
  244.                     //第一次乘的时候或者当前位置是0  
  245.                     last_res = 0x0;  
  246.                 } else {  
  247.                     //取得上一次当前位置的值  
  248.                     last_res = temp_res[k] - 0x30;  
  249.                 }  
  250.                 temp_mul = (num2[i] - 0x30) * (num1[j] - 0x30) + flag + last_res;//保存每一位的乘积  
  251.                 temp = temp_mul / 10;  
  252.                 if (temp > 0) {  
  253.                     //有余数  
  254.                     flag = temp;  
  255.                 } else {  
  256.                     flag = 0x0;  
  257.                 }  
  258.                 temp_res[k--] = (temp_mul % 10) + 0x30;  
  259.             }  
  260.             if (temp > 0 || temp_res[0] == 0x0) {  
  261.                 //每一次循环结束检查最高位以及那些结果不为k位数的  
  262.                 temp_res[k] = flag + 0x30;  
  263.             }  
  264.             flag = 0x0;//重置  
  265.         }  
  266.         k = len1 + len2;  
  267.         strncpy(res, temp_res, k);  
  268.         res[k] = '\0';  
  269.         k++;//包含'\0'的长度  
  270.         earse_zero(res, &k);  
  271.         free(temp_res);  
  272.     }  
  273. }  
  274.   
  275. //*num待计算阶乘的数的大小,*len该数的长度  
  276. int get_fac_allocate_num(const char *num, const int *len)  
  277. {  
  278.     int i, allocate_num = 0;  
  279.     int data = atoi(num);  
  280.   
  281.     for (i = 1; i < *len; i++) {  
  282.         allocate_num += i*9*pow(10, i-1);  
  283.     }  
  284.     allocate_num += *len*(data-pow(10, i-1)+1);//加上剩下的  
  285.   
  286.     return allocate_num;  
  287. }  
  288.   
  289. //阶乘  
  290. void big_fac(const char *num, char *res)  
  291. {  
  292.     int len = strlen(num), data;  
  293.     int len1, len2;  
  294.     int i, j, k, m, l;  
  295.     char *temp_res, temp, temp_mul, last_res;  
  296.     char flag = 0x0;  
  297.   
  298.     data = atoi(num);  
  299.     if (data > 2) {  
  300.         m = get_fac_allocate_num(num, &len);  
  301.         temp_res = (char *)malloc(m*3);//前m个字节保存计算结果,后2块保存数据  
  302.         memset(temp_res, 0, m*3);  
  303.         strncpy(temp_res+m-len, num, len);  
  304.         for (l = data - 1; l >= 2; l--) {  
  305.             //乘法执行*num-2次  
  306.             memcpy(temp_res+m, temp_res, m);//之前用strncpy居然没拷贝进去,发现strncpy碰到0就不拷贝了,那要参数n干啥  
  307.             sprintf(&temp_res[2*m], "%d", l);  
  308.             len1 = ystrlen(&temp_res[2*m-1]);//数据是倒着存储的,得倒着算长度  
  309.             len2 = strlen(&temp_res[2*m]);  
  310.             for (i = len2 - 1; i >= 0; i--) {  
  311.                 //k = len1 + i;  
  312.                 k = m - len2 + i;//定位到最后面那个数  
  313.                 for (j = 1; j <= len1; j++) {  
  314.                     //尽可能减少循环 每次的结果都是加了上次的结果 避免再把结果加起来  
  315.                     if (i == len2 - 1 || temp_res[k] == 0x0) {  
  316.                         //第一次乘的时候或者当前位置是0  
  317.                         last_res = 0x0;  
  318.                     } else {  
  319.                         //取得上一次当前位置的值  
  320.                         last_res = temp_res[k] - 0x30;  
  321.                     }  
  322.                     temp_mul = (temp_res[2*m+i] - 0x30) * (temp_res[2*m-j] - 0x30) + flag + last_res;//保存每一位的乘积  
  323.                     temp = temp_mul / 10;  
  324.                     if (temp > 0) {  
  325.                         //有余数  
  326.                         flag = temp;  
  327.                     } else {  
  328.                         flag = 0x0;  
  329.                     }  
  330.                     temp_res[k--] = (temp_mul % 10) + 0x30;  
  331.                 }  
  332.                 if (temp > 0) {  
  333.                     //每一次循环结束检查最高位以及那些结果不为k位数的  
  334.                     temp_res[k] = flag + 0x30;  
  335.                 }  
  336.                 flag = 0x0;//重置  
  337.             }  
  338.         }  
  339.         if (temp > 0) {  
  340.             //有进位  
  341.             strncpy(res, &temp_res[k], m - k);  
  342.             res[m - k] = '\0';  
  343.         } else {  
  344.             strncpy(res, &temp_res[k+1], m - k - 1);  
  345.             res[m-k-1] = '\0';  
  346.         }  
  347.         free(temp_res);  
  348.     } else {  
  349.         sprintf(res, "%d", data);  
  350.         if (res[0] == 0x30) {  
  351.             res[0] = 0x31;  
  352.         }  
  353.     }  
  354. }  
  355.   
  356. void show_choice()  
  357. {  
  358.     printf("**************大数计算问题****************\n");  
  359.     printf("*请选择操作类型                          *\n");  
  360.     printf("*1.加法                            2.减法*\n");  
  361.     printf("*3.乘法                            4.阶乘*\n");  
  362.     printf("******************5.退出******************\n");  
  363.     printf("******************************************\n");  
  364. }  
  365.   
  366. void show_input(const char *choice)  
  367. {  
  368.     char a[500], b[500], c[1000000];  
  369.     switch (*choice) {  
  370.     case 1:  
  371.         printf("请输入加数(输入不是数字,后果自负): ");  
  372.         scanf("%s", a);  
  373.         printf("请输入被加数(输入不是数字,后果自负): ");  
  374.         scanf("%s", b);  
  375.         if (a[0] >= 0x30 && a[0] <= 0x39 || a[0] == '-' && b[0] >= 0x30 && b[0] <= 0x39 || b[0] == '-') {  
  376.             if (a[0] == '-' && b[0] == '-') {  
  377.                 big_add(&b[1], &a[1], c);  
  378.                 printf("结果为: -%s\n", c);  
  379.             } else if (a[0] == '-' && b[0] != '-') {  
  380.                 big_sub(b, &a[1], c);  
  381.                 printf("结果为: %s\n", c);  
  382.             } else if (a[0] != '-' && b[0] == '-') {  
  383.                 big_sub(a, &b[1], c);  
  384.                 printf("结果为: %s\n", c);  
  385.             } else {  
  386.                 big_add(a, b, c);  
  387.                 printf("结果为: %s\n", c);  
  388.             }  
  389.         } else {  
  390.             printf("请输入整数\n");  
  391.         }  
  392.         break;  
  393.     case 2:  
  394.         printf("请输入减数(输入不是数字,后果自负): ");  
  395.         scanf("%s", a);  
  396.         printf("请输入被减数(输入不是数字,后果自负): ");  
  397.         scanf("%s", b);  
  398.         if (a[0] >= 0x30 && a[0] <= 0x39 || a[0] == '-' && b[0] >= 0x30 && b[0] <= 0x39 || b[0] == '-') {  
  399.             if (a[0] == '-' && b[0] == '-') {  
  400.                 big_sub(&b[1], &a[1], c);  
  401.                 printf("结果为: %s\n", c);  
  402.             } else if (a[0] == '-' && b[0] != '-') {  
  403.                 big_add(&a[1], b, c);  
  404.                 printf("结果为: -%s\n", c);  
  405.             } else if (a[0] != '-' && b[0] == '-') {  
  406.                 big_add(a, &b[1], c);  
  407.                 printf("结果为: %s\n", c);  
  408.             } else {  
  409.                 big_sub(a, b, c);  
  410.                 printf("结果为: %s\n", c);  
  411.             }  
  412.         } else {  
  413.             printf("请输入整数\n");  
  414.         }  
  415.         break;  
  416.     case 3:  
  417.         printf("请输入乘数(输入不是数字,后果自负): ");  
  418.         scanf("%s", a);  
  419.         printf("请输入被乘数(输入不是数字,后果自负): ");  
  420.         scanf("%s", b);  
  421.         if (a[0] >= 0x30 && a[0] <= 0x39 || a[0] == '-' && b[0] >= 0x30 && b[0] <= 0x39 || b[0] == '-') {  
  422.             if (a[0] == '-' && b[0] == '-') {  
  423.                 big_mul(&a[1], &b[1], c);  
  424.                 printf("结果为: %s\n", c);  
  425.             } else if (a[0] == '-' && b[0] != '-') {  
  426.                 big_mul(&a[1], b, c);  
  427.                 printf("结果为: -%s\n", c);  
  428.             } else if (a[0] != '-' && b[0] == '-') {  
  429.                 big_mul(a, &b[1], c);  
  430.                 printf("结果为: -%s\n", c);  
  431.             } else {  
  432.                 big_mul(a, b, c);  
  433.                 printf("结果为: %s\n", c);  
  434.             }  
  435.         } else {  
  436.             printf("请输入整数\n");  
  437.         }  
  438.         break;  
  439.     case 4:  
  440.         printf("请输入待计算阶乘的数(缓冲有限,最好不要超过7位数):");  
  441.         scanf("%s", a);  
  442.         if (strlen(a) <= 7) {  
  443.             if (a[0] < 0x30 || a[0] > 0x39) {  
  444.                 printf("请输入自然数\n");  
  445.             } else {  
  446.                 big_fac(a, c);  
  447.                 printf("%s! = %s\n", a, c);  
  448.             }  
  449.         } else {  
  450.             printf("数据太大,无法计算\n");  
  451.         }  
  452.         break;  
  453.     }  
  454. }  
  455. int main(int argc, char *argv[])  
  456. {  
  457.     char choice[100];  
  458.   
  459.     while (1) {  
  460.         show_choice();  
  461.         scanf("%s", choice);  
  462.         if (choice[0] >= '1' && choice[0] <= '4' && choice[1] == '\0') {  
  463.             choice[0] -= 0x30;  
  464.             show_input(choice);  
  465.         } else if (choice[0] == '5' && choice[1] == '\0') {  
  466.             printf("谢谢使用!\n");  
  467.             break;  
  468.         } else {  
  469.             printf("无效的输入(请看大屏幕)\n");  
  470.         }  
  471.     }  
  472.   
  473.     return 0;  
  474. }  

下边是程序运行截图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值