| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 8535 人关注过本帖, 1 人收藏
标题:高精度算法
只看楼主 加入收藏
zansunny
Rank: 2
来 自:石家庄
等 级:论坛游民
帖 子:60
专家分:72
注 册:2010-5-30
结帖率:100%
收藏(1)
 问题点数:0 回复次数:5 
高精度算法
#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;
    }
搜索更多相关主题的帖子: 算法 高精度 
2010-10-07 16:47
chao41091153
Rank: 2
等 级:论坛游民
帖 子:39
专家分:33
注 册:2010-5-26
收藏
得分:0 
  牛牛牛牛牛牛牛
2010-10-16 06:56
youhh
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2012-7-17
收藏
得分:0 
牛!!!
2012-07-17 11:31
狗尾巴狼
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2015-9-23
收藏
得分:0 
啊,好困难
2015-09-23 14:02
supernoob
Rank: 1
等 级:新手上路
帖 子:1
专家分:0
注 册:2016-2-10
收藏
得分:0 
灰常感谢,很详细的注释,对初学小白帮助很大
2016-02-10 12:15
快速回复:高精度算法
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.025211 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved