大数相除(相减的变形)

大数除法是四则运算里面最难的一种。不同于一般的模拟,除法操作不是模仿手工除法,而是利用减法操作来实现的。其基本思想是反复做除法,看从被除数里面最多能减去多少个除数,商就是多少。逐个减显然太慢,要判断一次最多能减少多少个整数(除数)的10的n次方。

以7546除以23为例:

    先用7546减去23的100倍,即减去2300,可以减3次,余下646,此时商就是300 (300=100*3);

    然后646减去23的10倍,即减去230,可以减2次,余下186,此时商就是320 (320=300+10*2);

    然后186减去23,可以减8次,余下2,此时商就是328 (328=320+1*8);

    因为2除以23的结果小于1,而我们又不用计算小数点位,所以不必再继续算下去了。

下面是C语言的两个正大数相除的参考代码,计算结果中没有小数:

#include<stdio.h>
#include<string.h> 
#define MAX 1000    // 大数的最大位数 

// 注: 
// 本代码在以下博客代码中进行修改: 
// http://www.cnblogs.com/javawebsoa/archive/2013/08/01/3231078.html
// 


/*
  函数SubStract功能:
  用长度为len1的大整数p1减去长度为len2的大整数p2
  结果存在p1中,返回值代表结果的长度
  不够减:返回-1 , 正好够:返回0
*/ 
int SubStract(int *p1, int len1, int *p2, int len2)
{
    int i;
    if(len1 < len2)
        return -1;
    if(len1 == len2 )
    {                        // 判断p1 > p2
        for(i = len1-1; i >= 0; i--)
        {
            if(p1[i] > p2[i])   // 若大,则满足条件,可做减法
                break;
            else if(p1[i] < p2[i]) // 否则返回-1
                return -1;
        }
    }
    for(i = 0; i <= len1-1; i++)  // 从低位开始做减法
    {
        p1[i] -= p2[i];         // 相减 
        if(p1[i] < 0)           // 若是否需要借位
        {   // 借位 
            p1[i] += 10;
            p1[i+1]--;
        }
    }
    for(i = len1-1; i >= 0; i--)  // 查找结果的最高位
    {
        if( p1[i] )             //最高位第一个不为0
            return (i+1);       //得到位数并返回
    } 
    return 0;                   //两数相等的时候返回0
}


/*
  大数除法---结果不包括小数点 
  num1 被除数
  num2 除数 
  sum  商,存放计算的结果,即:num1/num2=sum
  返回数组sum的有效长度,即商的位数 
*/ 
int Division(char num1[], char num2[], char sum[])
{
    int k, i, j;
    int len1, len2, len=0;     //大数位数
    int dValue;                //两大数相差位数
    int nTemp;                 //Subtract函数返回值
    int num_a[MAX] = {0};      //被除数
    int num_b[MAX] = {0};      //除数
    int num_c[MAX] = {0};      //商 

    len1 = strlen(num1);       //获得大数的位数
    len2 = strlen(num2);
    
    //将数字字符转换成整型数,且翻转保存在整型数组中 
    for( j = 0, i = len1-1; i >= 0; j++, i-- )
        num_a[j] = num1[i] - '0';
    for( j = 0, i = len2-1; i >= 0; j++, i-- )
        num_b[j] = num2[i] - '0';

    if( len1 < len2 )          //如果被除数小于除数,直接返回-1,表示结果为0
    {
        return -1;
    }
    dValue = len1 - len2;      //相差位数
    for (i = len1-1; i >= 0; i--)    //将除数扩大,使得除数和被除数位数相等
    {
        if (i >= dValue)
            num_b[i] = num_b[i-dValue];
        else                         //低位置0
            num_b[i] = 0;
    }
    len2 = len1;
    for(j = 0; j <= dValue; j++ )    //重复调用,同时记录减成功的次数,即为商
    {
        while((nTemp = SubStract(num_a, len1, num_b+j, len2-j)) >= 0)
        {
            len1 = nTemp;            //结果长度
            num_c[dValue-j]++;       //每成功减一次,将商的相应位加1
        }
    }
    // 计算商的位数,并将商放在sum字符数组中 
    for(i = MAX-1; num_c[i] == 0 && i >= 0; i-- );  //跳过高位0,获取商的位数 
    if(i >= 0)
        len = i + 1; // 保存位数 
    for(j = 0; i >= 0; i--, j++)     // 将结果复制到sum数组中 
        sum[j] = num_c[i] + '0';
    sum[j] = '\0';   // sum字符数组结尾置0 
    return len;      // 返回商的位数 


int main()
{
    int i;
    int len;                // 商的位数
    char num1[MAX] = "1234567899876543210";   // 第一个大数
    char num2[MAX] = "20160415123025";              // 第二个大数
    char sum[MAX] = {0};    // 计算结果 

    //scanf("%s", num1);      //以字符串形式读入大数
    //scanf("%s", num2);
    
    len = Division(num1, num2, sum); 
    
    //输出结果
    printf("%s\n  ÷\n%s\n  =\n", num1, num2);
    if( len>=0 )
    {
        for(i = 0; i < len; i++ )
            printf("%c", sum[i]);
    }
    else
    {
        printf("0");
    }
    printf("\n");
    
    return 0;
}

 

其实大数相除,就是一个不断相减的过程,这个相减需要从高位减到低位。其中还有一个关键就是我们需要借助大数相减这个函数,我们才好模拟相减。还需//v1.0
  #include <iostream>
 #include <cstring>
 void sub(char a[101],char b[101]);
 using namespace std;
 int main()
 {
  char a[101];
  char b[101];
  int cnt=0;
      cin>>a>>b;
          while(1)
          {
            sub(a,b);
            cnt++;
            cout<<"RUN ID is "<<cnt<<endl;
            if (strlen(a)<strlen(b))
                break;
          }
          cout<<"the result is"<<" ";
          cout<<cnt<<endl;
     cout<<a;
      
                return 0;
 }
 void sub(char a[101],char b[101])
 {
  char c[101];
  int i=strlen(a)-1;
  int j=strlen(b)-1;
  int k=0;
  int x;
  int y;
  int z;
  int up=0;
        while (i>=0 || j>=0)
          {
            i>=0?x=a[i]-'0':x=0;
            j>=0?y=b[j]-'0':y=0;
            z=x-y+up;
            z<0?z+=10,up=-1:up=0;
             c[k++]=z+'0';
            i--;
            j--;
          }
        up==-1?c[k]=1+'0':k--;
             i=0;
               while (k>=0)
            {
                  a[i++]=c[k--];
            }
            a[i]='/0';
            
            while (a[0] =='0')
            {
               for(j=0; j-1<i; j++)
                   a[j]=a[j+1];
            }
    
 }要一个函数判断我们被减数是否>=减数,这样我们就可以很好的手工模拟除法过程了。

#include <iostream>
    #include <cstring>
    #include <cmath>
    using namespace std;
    int lenth(int n)//求数字长度(位数)函数
    {
    int i=0;
      while(n>0)
       {
       n/=10;
       i++;
       }
        return i;
    }
        int main()
    {
    char a[102];
    int b;
        cin>>a>>b;//输入除数与被除数
        //cout<<lenth(b)<<endl;
    char sum[102];
    int i;
    int j=0;
    int yu_shu;
    int part_of_a=0;
       for (i=0; i<lenth(b); i++)
       {
           part_of_a+=(a[i]-'0')*(int)pow(10.0,lenth(b)-i-1);
       }
              //cout<<part_of_a<<endl;
          while ( i<=strlen(a) )
            {
            sum[j]=part_of_a/b;
        
            sum[j]==0 ? yu_shu=part_of_a : yu_shu=part_of_a-b*sum[j];
                sum[j]=sum[j]+'0';
                    //cout<<"sum["<<j<<"] is "<<sum[j]<<endl;
                part_of_a=yu_shu*10+a[i++]-'0';
                j++;
            }
              sum[j]='/0';
              int L=strlen(sum);
              while( L>1&∑[0]=='0')
                {
                  for(j=0; j-1<L; j++ )
                      sum[j]=sum[j+1];
                     L=strlen(sum);
                }
              cout<<sum;
       return 0;
       
    }

 

 

//v1.2
 #include <iostream>
 #include <cstring>
 void sub(char a[102],char b[102]);
 void conect(char d[],char c);
 using namespace std;
 int main()
 {
  char a[102];
  char b[102];
         cin>>a>>b;
         char sum[102];
  char part_of_a[102];
  
  
  int i;
  int j=0;
  int cnt=0;
  int lenth_of_a=strlen(a);
  int lenth_of_b=strlen(b);
    if( lenth_of_a==lenth_of_b&&strcmp(a,b)<0 || lenth_of_a<lenth_of_b)//除数小于被除数
    {
        cout<<"0"<<endl;
        cout<<"0"<<endl;
    }
    else  // 除数大于被除数
    {
           
                 for (i=0; i<lenth_of_b; i++)// 取 被除数a的一部分赋给part_of_a
                     {
                    part_of_a[i]=a[i];
                        }
                    part_of_a[i]='/0';
                if ( strcmp(part_of_a,b)<0)//如果当part_of_a和b长度相等而part_of_a又小一点时,加长part_of_a
                        conect(part_of_a,a[i++]);
                    while ( i<=lenth_of_a )
                    {                        
                                while(1)
                                {
                                    sub(part_of_a,b);
                                    cnt++;//计数器
                                    if ( strlen(part_of_a)<strlen(b) || 
                                            strlen(part_of_a)==strlen(b)&&strcmp(part_of_a,b)<0)
                                                break;
                                //减到所得数小减数为止
                                }
                                    sum[j++]=cnt+'0';
                                    cnt=0;
                    while ( 1 )
                            {
                                  conect(part_of_a,a[i++]);
                                  if (strcmp(part_of_a,b)>=0 && strlen(part_of_a)==lenth_of_b
                                      || strlen(part_of_a)>lenth_of_b 
                                      || i==lenth_of_a+1 )    // 这点是关键,就不写注释了,大家用这个算法写的时候先自己琢磨,如果搞不定可以来看看。
                                       break;
                                sum[j++]='0';
                            }
                    }
        
        sum[j]='/0';
       cout<<sum<<endl;
          if(strlen(part_of_a)>0)
                cout<<part_of_a<<endl;
          else 
                cout<<"0"<<endl;
    }
     
                return 0;
 }

 void sub(char a[102],char b[102])//减法函数
 {
  char c[101];
  int i=strlen(a)-1;
  int j=strlen(b)-1;
  int k=0;
  int x;
  int y;
  int z;
  int up=0;
        while (i>=0 || j>=0)
          {
            i>=0?x=a[i]-'0':x=0;
            j>=0?y=b[j]-'0':y=0;
            z=x-y+up;
            z<0?z+=10,up=-1:up=0;
             c[k++]=z+'0';
            i--;
            j--;
          }
        up==-1?c[k]=1+'0':k--;
             i=0;
               while (k>=0)
            {
                  a[i++]=c[k--];
            }
            a[i]='/0';
            //清除多于的零
            while (a[0] =='0')
            {
               for(j=0; j-1<i; j++)
                   a[j]=a[j+1];
            }
 }
 
 
 void conect(char d[],char c)// 加长part_of_a函数.
   {
   int i=strlen(d);
      d[i++]=c;
      d[i]='/0';
   }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值