NOJ 1149高精度乘法(另含高精度加、减&除详解)

来源:互联网 发布:redis 数据库的数量 编辑:程序博客网 时间:2024/06/05 18:38

#include <iostream>
using namespace std;

const long MAXN = 100000;

inline long& len(long* a)
{
 return a[MAXN-1];
}

void copy(long* to, long* scr)
{
 len(to) = len(scr);
 memcpy(to,scr,sizeof(long)*len(to));
}

void change(char* s,long l, long* a)//l是s的长度
{
 long i,j(0),cnt(0),k;

 if (l <= 4)
 {
  for (i=0; i<l; i++)
   j = j*10 + s[i] - '0';
  a[len(a)++] = j;
 }
 else
 {
  for (i=l-4; i<l; i++)
   j = j*10 + s[i] - '0';
  a[len(a)++] = j;
  s[l-4] = '/0'; //截断刚才的4位
  change(s, l-4, a);
 }
}

void cheng(long* a, long* b, long* c)
{
 long i,j;
 len(c) = len(a) + len(b);
 memset(c,0,sizeof(long)*len(c));
 
 for (i=0; i<len(a); i++)
  for (j=0; j<len(b); j++)
  {
   c[i+j] += a[i] * b[j];
   c[i+j+1] += c[i+j] / 10000;
   c[i+j] %= 10000;
  }
 while(len(c) > 1 && c[len(c)-1] == 0) len(c)--;
}
void print(long* a)
{
 long i;
 printf("%ld",a[len(a)-1]);
 
 for (i=len(a)-2; i>=0; i--)
  printf("%04ld",a[i]);
 printf("/n");
}

int main(void)
{
 long i,n,a[MAXN],b[MAXN],c[MAXN];
 char s[10000];

 while(scanf("%s",s) == 1)
 {
  len(a) = 0;//需要这样
  change(s,strlen(s),a);
  while(len(a) > 1 && a[len(a)-1] == 0) len(a)--; //去前导零
 
  scanf("%s",s); len(b) = 0;
  change(s,strlen(s),b);
 
  cheng(a,b,c);
 
  print(c);
 }
 return 0;
}

 

o下面是一个类似于strlen()的函数,在这个高精度计算的过程中都要用到~
oconst long MAXN = 100000;//一个很大的数
oinline long& len(long* a)
o{
o return a[MAXN-1];
o}

o为什么返回一个引用,是为了可以存在如下语句len(a) = 0; len(a)++;等等.
o其实本质上写这个函数的目的是少用一个len变量,一个数组就要对应一个len变量,要么用struct,要么用很多len变量.这两者都挺麻烦的,所以就想到搞了这么一个函数.
o当然,绝对不是说不能用struct,不能用别的变量记录长度.
 
ovoid change(char* s, long* a)
o{
o long i,j;
o len(a) = strlen(s);
o memset(a,0,sizeof(long)*len(a));
o for (i=0,j=len(a)-1; i<len(a); i++,j--)
o a[j] = s[i] - '0';
o while(len(a) > 1 && a[len(a)-1] == 0) len(a)--;(把高位的0出去?我的标注)
o}
o将字符串s转换成long数组a,红色的字可以将s串倒置存入a数组
 
ovoid print(long* a)
o{
o long i;
o for (i=len(a)-1; i>=0; i--)
o printf("%ld",a[i]);
o printf("/n");
o}
oprint()函数用于输出一个a数组,也就是打印一个高精度数,注意要反过来打印~
 
ovoid copy(long* to, long* scr)
o{
o len(to) = len(scr);
o memcpy(to,scr,sizeof(long)*len(to));
o}

ovoid jia(long* a, long* b, long* c)//实现c = a + b
o{
o long i,j = max(len(a), len(b));
o
o if (c == a)//为了实现a = a + b
o {
o for (i=len(c); i<len(b)+1; i++)//必要的清零
o c[i] = 0;
o len(c) = j + 1;
o }
o else if (c == b)//为了实现b = a + b
{
o jia(b,a,c);//J
return;//!!!!!!
}
用于将scr(源)复制到to(目标)中.
 
oelse
o {
o memset(c,0,sizeof(long)*(j+1));
o copy(c,a);
o len(c) = j + 1;
o }
o
o for (i=0; i<len(b); i++)
o {
o c[i] += b[i];
o c[i+1] += c[i] / 10;
o c[i] %= 10;
o }
o for (i=len(b); i<j; i++)//处理没有处理到的进位问题
o {
o c[i+1] += c[i] / 10;
o c[i] %= 10;
o }
o
o while(len(c) > 1 && c[len(c)-1] == 0) len(c)--;
o}
 
oc[i+1] += c[i] / 10;
oc[i] %= 10;
o这两句解决了进位的问题,而且对进不进都适用.更一般的,如果把其中的10换成n的话,就是一个n进制的加法(还需要改一下print函数)对后面的减法,乘法同样适用.
owhile(len(c) > 1 && c[len(c)-1] == 0) len(c)--;
o这句话的作用是去除前导零(如果是0除外)
 
o这里为了方便起见,把a赋值给c,然后在c的基础上加上b.
o注意,这样操作,不管c == a,还是c != a,都是正确的.想想是为什么?~
o还有,当c == b时,用了递归调用,其实也很好理解~
o下面是减法的代码:
 
ovoid jian(long* a, long* b, long* c) //c = a - b, 需要a >= b
o{
o long i;
o len(c) = len(a); //因为规定了a >= b
o if (c != a) copy(c,a);
o
o for (i=0; i<len(c); i++)
o {
o c[i] -= b[i];
o if (c[i] < 0)
o {
o c[i] += 10;
o c[i+1] -= 1;
o }
o }
o while(len(c) > 1 && c[len(c)-1] == 0) len(c)--;
o乘法代码:
 
ovoid cheng(long* a, long* b, long* c)// c = a * b
o{
o long i,j;
o len(c) = len(a) + len(b);
o memset(c,0,sizeof(long)*len(c));
o
o for (i=0; i<len(a); i++)
o for (j=0; j<len(b); j++)
o {
o c[i+j] += a[i] * b[j];
o c[i+j+1] += c[i+j] / 10;
o c[i+j] %= 10;
o }
o while(len(c) > 1 && c[len(c)-1] == 0) len(c)--;
o}
除法:
 
ovoid chu(long* a, long*b, long* c)//c = a / b
o{
o long *p = (long*)malloc(sizeof(long)*MAXN),
o *q = (long*)malloc(sizeof(long)*MAXN),
o *ten = (long*)malloc(sizeof(long)*MAXN),
o *tmp = (long*)malloc(sizeof(long)*MAXN),i,cnt;
o
o change("0",p); len(q) = 1; change("10",ten);
o len(c) = len(a);
o memset(c,0,sizeof(long)*len(c));
 
ofor (i=len(a)-1; i>=0; i--)
o {
o q[0] = a[i];
o copy(tmp,p); cheng(tmp,ten,p);// p = p * 10
o jia(p,q,p);// p = p + q
o
o cnt = 0;
o while(!xiao(p,b))//用减法试商的过程
o {
o jian(p,b,p);
o cnt++;
o }
o c[i] = cnt;
o }
o while(len(c) > 1 && c[len(c)-1] == 0) len(c)--;
o
o free(p); free(q); free(tmp); free(ten);//:-)
o}
}
如果能保证a,b无用的数据都是0的话(譬如是全局变量),那么处理多余进位问题的那个循环可以省略.