用指定位数的数组存储大整数,每一位对应一位,若大整数长度小于数组长度,索引已0开始的称高位,高位补零
即int a[10]存储数值为:123456
a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
0 0 0 0 1 2 3 4 5 6
简写:00000123456
这里的分析和实现为10进制当然可以类比为16进制,8进制,2进制
#1 大整数加法
分析:对位相加,若结果大于0,将结果-10,高位增1
实现如下:
/**
* a,b为大整数的两个加数,c存储大整数加后结果,len为数组长度(即大整数最多位数)
*/
void bignum_add(int a[],int b[],int c[],int len){
for(int i = 0; i <len; i++) c[i] = 0;
for(int i = len-1; i >= 0; i--){
c[i] += a[i]+b[i];
if( c[i] >= 10){
c[i]-=10;
c[i-1] +=1;
}
}
}
#2 大整数减法
分析:对位相减后,若结果小于0,高位借一,将结果+10
实现:
void big_subtract(int a[],int b[],int len){
int j;
for(j = 0; j < len; j++) if(a[j] != 0) break;
for(int i = len-1; i >= j; i--){
a[i] = a[i]-b[i];
if( a[i] < 0){
a[i-1]-=1;
a[i]+=10;
}
}
}
#3 大整数乘法
分析:
实现如下:
void bignum_multply(int a[],int b[],int c[],int len){
for(int z = 0; z < len; z++) c[z] = 0;
int i,j,k;
for(i = 0; i <len; i++) if(a[i] != 0) break; //i++得到的高位所有0的个数 len-i即a的位数
for(j = 0; j <len; j++) if(b[j] != 0) break; //同上 len-j即b的位数
int x = 0;
int y = 0;
for(int m = len-1; m >= i; m--,x++){
y = 0;
for(int n = len-1; n >= j; n--,y++){
c[len-1-(x+y)] += a[m]*b[n];
}
}
for(k = 0; k <len; k++) if(c[k] != 0) break;
for(; k < len; k++){
//printf("%d ",c[k]);
int time = 0;
while(c[k]>=10) {
c[k] -= 10;
time++;
}
c[k-1] += time;
}
//printf(" \n i=%d j=%d x=%d y=%d \n",i,j,x,y);
}
#4 大整数除法
分析:
例:1000 / 23
1‘ 我们要思考一个数是不是可以被一个数除
所以,判断除数是否小于被除数,若小于则不能被除
2’ 4000/23 = 173.91,可以表示为195,R=21
4000 - 2300*1 = 1700,
1700 - 230*7 = 90,
90 - 23*3 = 21 = R
根据如上步骤我们可以得出规律
1‘ 除数左移n位低位补0 ,最多移位为被除数位数-除数位数(被除数为n位,除数为m位,则商最多整数位为n-m位)
2’ 将除数左移位数 至 被除数长度时,若能减多少个数,个数对应商整数位,n=1,为个位,n=2为十位,n=3为百位......
3‘ 直至不能被减得到余数R
实现如下:
// 判断是否可除,即可减
int a_bigger_b(int a[],int b[],int len){
int i,j; //去除高位所有0后i,j为大数开始下标
for(i = 0; i < len; i++) if(a[i] != 0) break;
for(j = 0; j < len; j++) if(b[j] != 0) break;
// 被除数和除数位数不一样
if((len-i) != (len-j)) return (len-i) > (len-j);
for(; i < len; i++){
if(a[i] < b[i]) return 0;
else if(a[i] == b[j]) continue;
else return 1; //最高位大于则可以做减法
}
return 1;
}
//低位补领零或加零
// sub_or_add_zero(1,num1, num_maxlen,4);左移4位,地位补0
// sub_or_add_zero(0,num1, num_maxlen,3);右移三位,高位补0
void sub_or_add_zero(int flag,int b[],int len,int num){
int i; //去除高位所有0后i,j为大数开始下标
for(i = 0; i < len; i++) if(b[i] != 0) break;
if(flag==1){
//移位
for(; i < len; i++){
b[i-num] = b[i];
}
//移位后附0
for(int j = len -1; j >= (len-num);j--){
b[j]=0;
}
}
else if(flag==0){
//移位除零
for(int j = len - 1; j >= i; j--){
b[j] = b[j-num];
}
while(num){
b[i+num-1] = 0;
num--;
}
}
}
int bignum_divide(int a[],int b[],int len){
int i,j; //去除高位所有0后i,j为大数开始下标
for(i = 0; i < len; i++) if(a[i] != 0) break;
for(j = 0; j < len; j++) if(b[j] != 0) break;
int ans = 0;
sub_or_add_zero(1,b,len,j-i);
for(int k = 0; k <= (j-i); k++){ //长度相等循环一次
int time = 0;
while(a_bigger_b(a, b, len)==1){
big_subtract(a, b, len);
time++;
}
if(a_bigger_b(a, b, len) == a_bigger_b(b, a, len)) time = 1;
ans = ans*10 +time;
sub_or_add_zero(0,b,len,1);
}
return ans;
}
测试结果:
int main(void){
int num_maxlen = 100;
int num1[num_maxlen];
printf("-------pow(x,n) x^n--------\n");
int x = 2;
int n = 100;
bignum_pow(x,n,num1,num_maxlen);
printf("%d^%d result :",x,n);print_bignum(num1, num_maxlen);
printf("\n---------------\n");
int num2[num_maxlen];
bignum_pow(3,1,num2,num_maxlen);
printf("-------bitnum to add--------\n");
int num3[num_maxlen];
printf("the bignums are :[");print_bignum(num1, num_maxlen);printf("] , [");print_bignum(num2, num_maxlen);printf("]");
bignum_add(num1,num2,num3,num_maxlen);
//big_subtract(num1,num2,num3,num_maxlen);
printf("\nresult :");print_bignum(num3, num_maxlen);
printf("\n---------------\n");
printf("-------bitnum to multply--------\n");
int num4[num_maxlen];
printf("the bignums are :[");print_bignum(num1, num_maxlen);printf("] , [");print_bignum(num2, num_maxlen);printf("]");
bignum_multply(num1,num2,num4,num_maxlen);
printf("\nresult :");print_bignum(num4, num_maxlen);
printf("\n---------------");
printf("-------biStnum to divide--------\n");
printf("the bignums are :[");print_bignum(num1, num_maxlen);printf("] , [");print_bignum(num2, num_maxlen);printf("]");
printf("\nresult : ans = %d R=",bignum_divide(num1, num2, num_maxlen));print_bignum(num1, num_maxlen);
printf("\n---------------");
return 0;
}
result:
-------pow(x,n) x^n-------------------------
2^100 result :1267650600228229401496703205376
---------------------------------------------------
-------bitnum to add-------------------------
the bignums are :[1267650600228229401496703205376] , [3]
result :1267650600228229401496703205379
---------------------------------------------------
-------bitnum to multply---------------------
the bignums are :[1267650600228229401496703205376] , [3]
result :3710295180068468820448101096151128
----------------------biStnum to divide--------
the bignums are :[1267650600228229401496703205376] , [3]
result : ans = 1431655765 R=1
-----------------------------------------------------