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+b
bigNum 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){ // 低精度 b
bigNum 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){ // 高精度 b
bigNum 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/b
bigNum 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;
// 无需翻转也能为0
r = 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>b
bn_sub = sub(bn_str1, bn_str2);
}else if(compare(bn_str1, bn_str2) == -1){ // a<b
bn_sub = sub(bn_str2, bn_str1);
printf("-");
} else{ // a=b
bn_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>b
bigNum bn_div = div(bn_str1, bn_str2, bn_r);
print(bn_div);
}
else if(compareSort(bn_str1, bn_str2) == -1) printf("0"); // a<b
else printf("1"); // a=b
return 0;
}
不太想码字了,刚考完密码学第一次编程考试,人生啊,就是如此艰难。溜了溜了,睡觉。