C语言 实现大数四则运算
所谓大数,就是数字非常(*100)的大,不管是int还是long long int都存储不下的数,如何进行加减乘除四则运算,这种情况在计算机的运算中还是很常见的,现将大致思路写上,并附上代码以供参考。
整体思路
首先数据必然是不能以int或者long long int存储,那么只能以字符串或者字符数组的形式存储。而且实际上,以字符数组接收数据最佳,然后把字符数组转化为int数组,再对数字进行计算。
其次,联想起我们小学二年级所学的加减乘除四则运算,我们会发现一个最基本的规律:
加减乘:从右往左计算
除法:从左往右计算
这就提示我们,数据需要进行一下处理,因为输入的数据是不定长的,所以我们需要把数据对齐。也就是说我们需要在加减乘,将数据倒过来,个位对个位,十分位对十分位;但是在除法中,我们只要按从左往右接收数据就可。
数据结构
int数组没有不能像字符数组那样,可以直接获取长度,所以最初想法就是在转化int数组的时候,再加上一个变量len,标记数组长度。
struct bigNum{int n[MAX];int len;bigNum(){memset(n, 0, sizeof(n));len = 0;}};
数据处理
根据上边的思路,我们需要将char型数组转化为int型数组,而且是倒序,这样保证从个位开始对齐,方便加减乘运算,而除法只需要将char型数组转化为int型数组就可。
当然还有一些其他的工具,比如比较两个bigNum的大小,这在减法和除法上需要用到,还有除法采用的是减法思想,所以除法的数组顺序也要有个调整。
// 加减乘处理使用bigNum transfer(char str[]){bigNum bn;bn.len = strlen(str);int i;for(i=0; i<bn.len; i++)bn.n[i] = str[bn.len-1-i] - '0';return bn;}// 除法处理使用bigNum transferSort(char str[]){bigNum bn;bn.len = strlen(str);int i;for(i=0; i<bn.len; i++)bn.n[i] = str[i] - '0';return bn;}// 加减乘处理使用int compare(bigNum a, bigNum b){if(a.len > b.len) return 1;else if(a.len < b.len) return -1;else{int i;for(i=a.len-1; i>0; i--){ //高位比较if(a.n[i] > b.n[i]) return 1;else if(a.n[i] < b.n[i]) return -1;else return 0;}}}// 除法处理使用int compareSort(bigNum a, bigNum b){if(a.len > b.len) return 1;else if(a.len < b.len) return -1;else{int i;for(i=0; i<a.len; i++){ //高位比较if(a.n[i] > b.n[i]) return 1;else if(a.n[i] < b.n[i]) return -1;else return 0;}}}// 倒序,除法用void reverse(int a[], int len){int i;for(i=0; i<len/2; i++){int temp = a[i];a[i] = a[len-1-i];a[len-1-i] = temp;}}
大数加法
bigNum add(bigNum a, bigNum b){ // a+bbigNum c;int flag = 0;int len = (a.len > b.len) ? a.len : b.len;int i;for (i=0; i<len; i++){int temp = a.n[i] + b.n[i] + flag;flag = (temp >= 10) ? 1 : 0;c.n[c.len++] = temp % 10;}// 处理进位情况if(flag != 0)c.n[c.len++] = 1;return c;}
大数减法
bigNum sub(bigNum a, bigNum b){ // a-b 或 a+(-b)bigNum c;int len = (a.len > b.len) ? a.len : b.len;int i;for(i=0; i<len; i++){if(a.n[i]<b.n[i]){a.n[i+1]--; //借一a.n[i] += 10; //当十}c.n[c.len++] = a.n[i] - b.n[i];}// 去除高位0 112-111=001,但是要保证有一位数while(c.n[c.len-1]==0 && c.len>1)c.len--;return c;}
大数乘法
// 高精度与低精度乘法运算,为高精度乘法运算使用bigNum sigMul(bigNum a, int b){ // 低精度 bbigNum c;int flag = 0;int i;for(i=0; i<a.len; i++){int temp = a.n[i]*b + flag;c.n[c.len++] = temp % 10;flag = temp/10;}while(flag){c.n[c.len++] = flag % 10;flag /= 10;}return c;}// 数组移位操作bigNum move(bigNum a, int index){bigNum b = bigNum();int i;b.len = a.len + index;for(i=0; i<a.len; i++){b.n[i+index] = a.n[i];}return b;}// 高精度乘法运算bigNum mul(bigNum a, bigNum b){ // 高精度 bbigNum c = bigNum();int i;for(i=0; i<b.len; i++){bigNum temp = sigMul(a, b.n[i]);bigNum temp_move = move(temp,i);c = add(c, temp_move);}return c;}
大数除法
其实可以用逆序,但是当前正序思维好捋一点。减法暂时实现了除数是个位数,多位的还没来得及调试,但是考完试不太想debug,先放个坑在这里,啥时候记得补了,再回来填。欢迎大佬进行指导。
// 高精度与低精度除法运算 逆序bigNum sigDiv(bigNum a, int b, int &r){bigNum c;c.len = a.len;int i;for(i=a.len-1; i>0; i--){ // 高位开始r = r*10 + a.n[i];if(r<b) c.n[i] = 0;else{c.n[i] = r/b;r %= b;}}while(c.n[c.len-1]==0 && c.len>1)c.len--;return c;}// 高精度除法运算bigNum div(bigNum a, bigNum b, bigNum r){ // 正序 计算大数 a/bbigNum c;c.len = a.len;int i;for(i=0; i<a.len; i++){ // 高位开始r.n[r.len++] = a.n[i];int flag = compareSort(r, b);if(flag == -1) c.n[i] = 0;else if(flag == 0){c.n[i] = 1;// 无需翻转也能为0r = sub(r, b);r.len = 0; // 结果为0,长度是1,这里需要处理,否则会多一位} else{// 做减法int index = 0;while(compareSort(r, b)==1){reverse(r.n, r.len);reverse(b.n, b.len);r = sub(r, b);reverse(r.n, r.len);index++;}c.n[i] = index;}}// 处理开头 b.n-1 个0 ,循环左移while(c.n[0]==0 && c.len>1){int k;for(k=0; k<c.len-1; k++)c.n[k] = c.n[k+1];c.len--;}return c;}
主函数代码
int main(){char str1[MAX], str2[MAX];scanf("%s%s", str1, str2);// ========================加减乘============================// 反序,加减乘都是从右到左//bigNum bn_str1 = transfer(str1);//bigNum bn_str2 = transfer(str2);//bigNum bn_add = add(bn_str1, bn_str2);//screenPrint(bn_add);/*bigNum bn_sub;if(compare(bn_str1,n_str2) == 1){ // a>bbn_sub = sub(bn_str1, bn_str2);}else if(compare(bn_str1, bn_str2) == -1){ // a<bbn_sub = sub(bn_str2, bn_str1);printf("-");} else{ // a=bbn_sub = sub(bn_str1, bn_str2);}screenPrint(bn_sub);*/// ========================除法============================// 正序,除是从左到右bigNum bn_str1 = transferSort(str1);bigNum bn_str2 = transferSort(str2);//reverse(bn_str1.n, bn_str1.len);//print(bn_str1);bigNum bn_r = bigNum();if(compareSort(bn_str1, bn_str2) == 1){ // a>bbigNum bn_div = div(bn_str1, bn_str2, bn_r);print(bn_div);}else if(compareSort(bn_str1, bn_str2) == -1) printf("0"); // a<belse printf("1"); // a=breturn 0;}
不太想码字了,刚考完密码学第一次编程考试,人生啊,就是如此艰难。溜了溜了,睡觉。
