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