大数–高精度运算【C语言】
鸽了这么多天,今天来学学ACM的入门知识
高精度–也就是数字位数太多需要我们自己定义来表示
我们可以直接用数组,
或者将值和数的长度封装成结构体来表示
#include<stdio.h>
#include<string.h>
#define MAXN 100000
typedef struct BigNum{
int len,val[MAXN];
} BigNum;
那我们知道大数不能和其他数据类型一样简单的用scanf,printf输入输出
所以需要自己定义
//大数存储
int string2num(char str[],int num[]){
int length = strlen(str);
for(int i = 0;i < length;i++){
num[i] = str[length - 1 - i] - '0';
}
return length;
}
//大数输出
void output(int num[],int length){
for(int i = length - 1;i >= 0;i--){
printf("%d",num[i]);
}
}
除了一位一位储存,也可以压位储存
请小伙伴尽情百度
下面说说大数运算
首先是大数的加法
可以手动模拟来寻找思路,
重点需要用carry来表示进位
int Add(int a[],int length_a,int b[],int length_b,int c[]){
int length_c,mod = 10,carry = 0,sum = 0;
length_c = length_a > length_b ? length_a:length_b;
for(int i = 0;i < length_c;i++){
sum = a[i] + b[i] + carry;
c[i] = sum % mod;
carry = sum / mod;
}
if(carry != 0) c[length_c++] = carry;
return length_c;
}
下面是结构体形式的源码
BigNum Add(BigNum A,BigNum B){
int mod = 10,carry = 0,sum = 0;
BigNum C;
C.len = A.len > B.len ? A.len : B.len;
for(int i = 0;i < C.len;i++){
sum = A.val[i] + B.val[i] + carry;
C.val[i] = sum % mod;
carry = sum / mod;
}
if(carry != 0) C.val[C.len++] = carry;
return C;
}
大数的减法
重点在于借位,同时也要注意0的处理
BigNum minus(BigNum A,BigNum B){
int mod = 10,borrow = 0,diff = 0;
BigNum C;
C.len = A.len > B.len ? A.len : B.len;
for(int i = 0;i < C.len;i++){
diff = A.val[i] - B.val[i] - borrow;
C.val[i] = diff % mod;
borrow = diff < 0? 1 : 0;
}
while(C.val[C.len - 1] == 0 && C.len > 1) C.len --;
return C;
}
大数的乘法
多位*一位与加法类似
//多位*一位
int multi(int a[],int len_a,int b,int c[]){
int rslt = 0,mod = 10,carry = 0;
int len_c = len_a;
for(int i = 0;i < len_c;i++){
rslt = a[i] * b + carry;
c[i] = rslt % mod;
carry = rslt / mod;
}
if(carry != 0) c[len_c ++] = carry;
return len_c;
}
多位 * 多位转化成多位 * 一位来做
int multi(int a[],int len_a,int b,int len_b,int c[]){
int sum = 0,mod = 10,carry = 0;
int len_c = len_a + len_b;
memset(c,0,len_c);
for(int j = 0;j < len_b;j++){
for(int i = 0;i < len_a;i++){
sum = c[i+j] + a[i] * a[b] +carry;
c[i+j] = sum % mod;
carry = sum / mod;
}
}
while(len_c == 0 && len_c > 0) len_c -- ;
return len_c;
}
最后是大数除法
注意要记录余数
举个多位 / 一位的栗子
//高精度除以低精度
BigNum divide(BigNum A,int b,int &rest){
int ans = 0,mod = 10;
BigNum C;
C.len = A.len;
memset(C.val, 0, C.len);
rest = 0;
for(int i = A.len - 1;i >= 0;i--){
ans = rest * mod + A.val[i];
C.val[i] = ans / b;
rest = ans % b;
}
while(C.val[C.len--] == 0 &&C.len > 0) C.len -- ;
return C;
}
多位 / 多位留给大家自己写啦
因为我还没写,没法分享源码了
多说一下
在运算类似 35654611365646486 +(-54487816151311531531315)这种时
需要自己用sig来记录数的正负,进而转换到上述运算中去。
明天见~