高精度算法

高 精 度 算 法
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <malloc.h>
int an,bn,fa=1,fb=1;         /* 把an,bn,k设为全局变量,an纪录第一个高精度数组的位数,bn纪录第二个高精度数组的位数,k纪录输出结果的位数*/
char b1[250], b2[250];           /*纪录需要计算的两个高精度数据  */
void input(int a1[],int a2[])    /*函数input为输入函数,用来纪录两个待计算的高精度数据,以数组首地址为参数.以实现返回两个高精度数据*/
{
    int i,ai=1,bi=1;
    scanf ( "%s%s", b1, b2 );                      /*输入两个高精度数据 */
    an = strlen( b1 );                             /*an纪录b1的位数 */
    bn = strlen( b2 );                            /*bn纪录b2的位数 */
    if(b1[0]==45) { an--; fa=-1;ai=0;}           /*判断数组的符号 */
    if(b2[0]==45) { bn--; fb=-1;bi=0;}
    for (i=0; i<an; i++,ai++) {a1[i]=b1[an-ai]-'0'; printf("%d",a1[i]);}     /*把字符形数据b1转为整数形数据,同样用数组纪录 */
    for (i=0; i<bn; i++,bi++) a2[i]=b2[bn-bi]-'0';    /* 同上  */
    return;
}
void addition(int a[],int b[],int q)              /*高精度加法运算*/
{
    int i,c[251]={0},k;
    if(fa*fb>0||q)
    {
        if(an>bn) k=an;
        else k=bn;                                            /*用k纪录结果的最小位数*/
        for(i=0;i<k;i++)
        {
            c[i]=a[i]+b[i]+c[i];
            c[i+1]=(int)c[i]/10;
            c[i]=(int)c[i]%10;
         }                                                 /*高精度加法运算过程*/
        if(c[k]) k++;                                     /*判断最后结果的位数*/
        if(fa<0&&q||fa<0) printf("-");
        for(i=k-1;i>=0;i--)  printf("%d",c[i]);         /*输出结果*/
        return;
    }
    else subtraction(a,b,1);
    return;
}


subtraction(int a[],int b[],int q)                      /*高精度减法运算*/
{
    int i,f=0,c[251]={0},k;
    if(fa*fb>0||q)
    {
        if(an>bn) k=an;
        else                                     /*用k纪录结果的最大位数*/
         { k=bn;
            for(i=k;a[i]<=b[i]&&i>=0;i--)
            if(a[i]<b[i]) f=1;                /*f纪录结果符号*/
           }


        if(!f)                                /*高精度减法运算过程*/
         for(i=0;i<k;i++)
         {
             if(a[i]<b[i])
             {     a[i+1]--;
                   a[i]+=10;
            }
            c[i]=a[i]-b[i];
          }
        else                                         /*当a<b时的处理*/
          for(i=0;i<k;i++)
            {
               if(b[i]<a[i])
               {   b[i+1]--;
                  b[i]+=10;
               }
               c[i]=b[i]-a[i];
             }
        while(!c[k-1]&&k>1) k--;                  /*判断最后结果的位数*/
        if(q&&(fa>0&&f||fa<0&&!f)||fa>0&&(fb>0&&!f||f&&!q)) printf("-");                      /*如果f为真是输出负号*/
        for(i=k-1;i>=0;i--) printf("%d",c[i]);
        return;
    }
    else addition(a,b,1);
}














void multiplication( int a[], int b[])                  /*高精度乘法运算*/
{
    int i, j, c[501] = {0},k;
    k = an + bn - 1;                          /*用k纪录结果的最大位数*/
    for(i = 0; i < an; i++)                  /*高精度乘法运算过程*/
     for(j = 0;j < bn; j++)
      {
        c[i+j] = a[i] * b[j] + c[i+j];
        c[i+j+1] = c[i+j] / 10 + c[i+j+1];
        c[i+j] = c[i+j] % 10;
      }
    while(!c[k]) k--;                          /*判断最后结果的位数*/
    if(fa*fb<0) printf("-");
    for(i = k; i >= 0; i--)  printf("%d",c[i]);     /*输出结果*/
}
main()
{
    int a[250]={0},b[250]={0};
    input(a,b);
    printf("\n%s+%s=",b1,b2);addition(a,b,0);
    printf("\n%s-%s=",b1,b2);subtraction(a,b,0);
    printf("\n%s*%s=",b1,b2);multiplication(a,b);
    getch();
}


1、 高精度除以低精度; 
算法:按照从高位到低位的顺序,逐位相除。在除到第j位时,该位在接受了来自第j+1位的余数后与除数相除,如果最高位为零,则商的长度减一。源程序如下: 
#include  <stdio.h> 
#define   N  500 
main() 

  int  a[N] = {0}, c[N] = {0}; 
  int  i, k, d, b; 
  char  a1[N];  
  printf("Input 除数:"); 
  scanf("%d", &b); 
  printf("Input 被除数:"); 
  scanf("%s", a1); 
  k = strlen(a1); 
  for(i = 0; i < k; i++)  a[i] = a1[k - i - 1] - '0'; 
  d = 0; 
  for(i = k - 1; i >= 0 ; i--) 
  { 
     d = d * 10 + a[i]; 
     c[i] = d / b; 
     d = d % b;      
  }   
  while(c[k - 1] == 0 && k > 1)  k--;  
  printf("商="); 
  for(i = k - 1; i >= 0; i--)  printf("%d", c[i]); 
  printf("\n余数=%d", d);    
}     


2、高精度乘以高精度(要求用尽可能少的存储单元); 
算法:用数组保存两个高精度数,然后逐位相乘,注意考虑进位和总位数。源程序如下: 
#include  <stdio.h> 
main() 

  int  a[240] = {0}, b[240] = {0}, c[480] = {0}; 
  int  i, j, ka, kb, k; 
  char  a1[240], b1[240]; 
  gets(a1);    
  ka = strlen(a1); 
  gets(b1);    
  kb = strlen(b1); 
  k = ka + kb; 
  for(i = 0; i < ka; i++)  a[i] = a1[ka-i-1] - '0'; 
  for(i = 0; i < kb; i++)  b[i] = b1[kb-i-1] - '0'; 
  for(i = 0; i < ka; i++) 
    for(j = 0; j < kb; j++) 
    { 
      c[i + j] = c[i + j] + a[i] * b[j]; 
      c[i + j +1] = c[i + j +1] + c[i + j]/10; 
      c[i + j] = c[i + j] % 10; 
    } 
  if(!c[k])  k--; 
  for(i = k-1; i >= 0; i--)  printf("%d", c[i]);        
}     


3、高精度除以高精度(要求用尽可能少的存储单元); 
算法:用计算机模拟手算除法,把除法试商转化为连减。 
#include  <stdio.h> 
#define   N  500 
int  bj(int a[], int b[], int k1, int k2)   /*比较大小函数*/ 

   int i, t, flag;       /*flag作标志位*/ 
   if(k1 < k2)  
     flag = 0;           /*被除数小于除数返回0*/ 
   else if(k1 > k2)  
          flag = 1;      /*被除数大于除数返回1*/ 
        else 
          {              /*被除数和除数位数相等则逐位进行比较*/ 
            i = k1; 
            t = 0; 
            while(t == 0 && i > 0) 
            { 
              if(a[i] > b[i]) {t = 1; flag = 1;} 
              else if(a[i] == b[i])  i--; 
              else  {t = 1; flag = 0;}        
            } 
            if(i == 0 && t == 0)  flag = 2;     /*被除数等于除数返回2*/ 
          } 
  return flag;           

int  jf(int a[], int b[], int k1, int k2)       /*减法运算*/ 

  int  i, k, d[N]; 
  for(i = 0; i < k2; i++)  d[i] = b[i];        /*把除数赋给数组d*/ 
  for(i = k2; i < N; i++)  d[i] = 0;          /*d数组无数据的高位置0*/ 
  k = k1 - k2 - 1;                            /*计算减法起始位置*/ 
  if(k < 0)  k = 0; 
  if(k > 0) 
  { 
    for(i = k2 - 1; i >= 0; i--)  d[i + k] = d[i];  /*移动减数位数与被减数对齐*/ 
    for(i = 0; i < k; i++)  d[i] = 0;            /*移动后的其余位置0*/ 
  }  
  for(i = 0; i < k1; i++) 
  { 
    if(a[i] >= d[i])  a[i] -= d[i]; 
    else 
    { 
      a[i + 1] = a[i + 1] - 1; 
      a[i] = 10 + a[i] - d[i];  
    }     
  }   
  return k; 

main() 

  int  a[N] = {0}, b[N] = {0}, c[N] = {0}, d[N] = {0}; 
  int  i, ka, kb, m, t, t1, t2, k, x, kd, kk; 
  char  a1[N], b1[N];  
  printf("Input 被除数:"); 
  scanf("%s", a1); 
  ka = strlen(a1); 
  for(i = 0; i < ka; i++)  a[i] = a1[ka - i -1] - '0'; 
  printf("Input 除数:"); 
  scanf("%s", b1); 
  kb = strlen(b1); 
  for(i = 0; i < kb; i++)  b[i] = b1[kb - i -1] - '0'; 
  kd = ka;    /*保存被除数位数  */ 
  t2 = bj(a, b, ka, kb); 
  m = 0; 
  do 
  { 
    while(a[ka - 1] == 0)  ka--; 
    t = bj(a, b, ka, kb);    
    if(t >= 1) 
    { 
      k = jf(a, b, ka, kb); 
      c[k]++;      
      if(k > m)  m = k; 
      t1 = 0; 
      for(i = k; i <= m; i++) 
      { 
        x = c[i] + t1; 
        c[i] = x % 10; 
        t1 = x / 10;     
      } 
      if(t1 > 0)  {m++; c[m] = t1;  }     
    }    
  }while(t == 1); 
  if(t2 == 0)  
  { 
    printf("商=0");  
    printf("\n余数="); 
    for(i = kd - 1; i >= 0; i--)  printf("%d", a[i]); 
    exit(1);  
  } 
  if(t2 == 2) 
  { 
    printf("商 = 1");  
    printf("\n余数 = 0"); 
    exit(1);  
  } 
  kk = kd; 
  while(!c[kd - 1])  kd--; 
  printf("商 = "); 
  for(i = kd - 1; i >= 0; i--)  printf("%d", c[i]); 
  while(!a[kk])  kk--; 
  printf("\n余数 = "); 
  if(kk < 0)  
  { 
    printf("0");  
    exit(1); 
  } 
  for(i = kk; i >= 0; i--)  printf("%d", a[i]); 

4、 N!,要求精确到P位(0〈P〈1000〉。 
算法:结果用数组a保存,开始时a[0]=1,依次乘以数组中各位,注意进位和数组长度的变化。源程序如下: 
#include   <stdio.h> 
#define    M   1000 
main() 

  int a[M], i, n, j, flag = 1; 
  printf("n="); 
  scanf("%d",&n); 
  printf("n!="); 
  a[0] = 1; 
  for(i = 1; i < M; i++) a[i] = 0; 
   for(j = 2; j <= n; j++) 
   { 
     for(i = 0; i < flag; i++) a[i] *= j; 
     for(i = 0; i < flag; i++) 
       if(a[i] >= 10) 
       { 
         a[i+1] += a[i]/10; 
         a[i] = a[i] % 10; 
         if(i == flag-1)  flag++; 
       } 
    } 
  for(j = flag - 1; j >= 0; j--) 
    printf("%d", a[j]); 

问题1. 麦森数 
【问题描述】形如2P-1的素数称为麦森数,这时P一定也是个素数。但反过来不一定,即如果P是个素数,2P-1不一定也是素数。到1998年底,人们已找到了37个麦森数。最大的一个是P=3021377,它有909526位。麦森数有许多重要应用,它与完全数密切相关。 
任务:从文件中输入P(1000<P<3100000),计算2P-1的位数和最后500位数字(用十进制高精度数表示) 
【输入格式】 
文件中只包含一个整数P(1000<P<3100000) 
【输出格式】 
第一行:十进制高精度数2P-1的位数。 
第2-11行:十进制高精度数2P-1的最后500位数字。(每行输出50位,共输出10行,不足500位时高位补0) 
不必验证2P-1与P是否为素数。 
【输入样例】 
1279 
【输出样例】 
386 
00000000000000000000000000000000000000000000000000 
00000000000000000000000000000000000000000000000000 
00000000000000104079321946643990819252403273640855 
38615262247266704805319112350403608059673360298012 
23944173232418484242161395428100779138356624832346 
49081399066056773207629241295093892203457731833496 
61583550472959420547689811211693677147548478866962 
50138443826029173234888531116082853841658502825560 
46662248318909188018470682222031405210266984354887 
32958028878050869736186900714720710555703168729087 
算法:2的幂可以转化成左移运算,为了提高运算速度,可每次左移10位,即每次乘210。对于个位单独考虑,每次左移一位。源程序如下: 
#include <stdio.h> 
#include <math.h> 
#define  MAX  100000 
main() 

   int p; 
   int i, j; 
   scanf("%d", &p); 
   printf("%d\n", (int)(p * log10(2.0)) + 1); 
   long  store[110] = {0}; 
   store[0] = 1; 
   int left = p % 10; 
   p /= 10; 
    for(i = 1; i <= p; i++) 
    { 
      for(j = 0; j <= 100; j++) 
        store[j] <<= 10; 
      for(j = 0; j <= 100; j++) 
      { 
        if(store[j] >= MAX) 
        { 
          store[j + 1] += store[j] / MAX; 
          store[j] %= MAX; 
        } 
      } 
    } 
    for(i = 1; i <= left; i++) 
    { 
      for(j = 0; j <= 100; j++) 
        store[j] <<= 1; 
      for(j = 0; j <= 100; j++) 
      { 
        if(store[j] >= MAX) 
        { 
          store[j + 1] += store[j] / MAX; 
          store[j] %= MAX; 
        } 
      } 
    } 
    store[0] -= 1; 
    for(i = 1; i < 100; i++) 
    { 
      if(store[i - 1] < 0) 
      { 
         store[i] -= 1; 
         store[i - 1] += MAX; 
      } 
      else 
        break; 
    } 
    for(i = 99; i >= 0; i--) 
    { 
      printf("%05d", store[i]); 
      if((100 - i) % 10 == 0) 
          printf("\n"); 
    } 

问题2. 有一个正整数N(N可能达到120位),它是由若干个不大于65535的正整数相乘而得到的。请把这个数分解成素数因子(质因子)的乘积。 
输入:输入文件只有一行为N的值。 
输出:(1)素数因子由小到大分行输出; 
(2)每一行输出一个素数因子和该素数因子的个数,用一个空格分开; 
(3)如果正整数N的分解中有一个以上的大于65535的素数,请按照(1)、(2)的要求输出分解中的小于65535的素数后,在下一行输出
“DATA  ERROR!”。 
算法:先将2到65535之间的所有素数保存在数组中,用这个数去除数组中的每一个数,得到一个质因数就打印出来。源程序如下: 
#include  <stdio.h> 
#include  <math.h> 
int length, temp[120]; 
int sushu(int a[]) 

  int i, j, k = 0, m; 
  for(i = 2; i <= 65537; i++) 
  { 
    m = sqrt(i); 
    for(j = 2; j <= m; j++) 
      if(i % j == 0)  break; 
    if(j > m) 
    { 
      a[k] = i; 
      k++;    
    }         
  } 
 return k;     

int divide(int a[], int k) 

  int i, d = 0; 
  for(i = length - 1; i >= 0; i--) 
  { 
     d = d * 10 + a[i]; 
     temp[i] = d / k; 
     d = d % k;      
  }   
  if(!d) 
    { 
      while(temp[length - 1] == 0 && length > 1)  length--; 
      for(i = 0; i < length; i++) 
      { 
        a[i] = temp[i]; 
        temp[i] = 0;      
      } 
      for(i = length; i < 120; i++) a[i] = 0;    
    } 
    else  
      for(i = 0; i < length; i++)  temp[i] = 0; 
  return d;     

main() 

  int i, k, s, d;       /*s计数器; d余数*/ 
  int a[6600], b[120] = {0}, c[120] = {0}; 
  char b1[120]; 
  gets(b1); 
 length = strlen(b1); 
  for(i = 0; i < length; i++)  b[i] = b1[length - i - 1] - '0'; 
  k = sushu(a); 
  for(i = 0; i < k; i++) 
  { 
    s = 0; 
    d = divide(b, a[i]); 
    while(!d) 
    { 
      s++; 
      d = divide(b, a[i]);         
    } 
    if(i == k - 1)  
 
    {  
      printf("Data Error!"); 
      break; 
    }

你可能感兴趣的:(算法)