概念
所谓大数相乘(Multiplication algorithm),就是指数字比较大,相乘的结果超出了基本类型的表示范围,所以这样的数不能够直接做乘法运算。
思路
目前大数乘法算法主要有以下几种思路:
-
模拟小学乘法:最简单的乘法竖式手算的累加型;
-
分治乘法:最简单的是Karatsuba乘法,一般化以后有Toom-Cook乘法;
-
快速傅里叶变换FFT:(为了避免精度问题,可以改用快速数论变换FNTT),时间复杂度O(N lgN lglgN)。具体可参照Schönhage–Strassen algorithm;
-
中国剩余定理:把每个数分解到一些互素的模上,然后每个同余方程对应乘起来就行;
-
Furer’s algorithm:在渐进意义上FNTT还快的算法。
模拟算法
本文主要讲简单易懂的模拟算法
两个大数 分别存于2个数组,结果存于一个数组 数组长为两个数组之和
针对这类问题 主要在于大数的表示方式,以及数值相关进位。
大数相乘 AxB
char *BigNumMultipy( char num1[], char num2[])
{
int len1 = strlen(num1);
int len2 = strlen(num2);
/* 分配一个空间,用来存储运算的结果,num1长的数 * num2长的数,结果不会超过num1+num2长 */
int res[len1+len2];
int i, j, k;
/* 先不考虑进位问题,根据竖式的乘法运算,num1的第i位与num2的第j位相乘,结果应该存放在结果的第i+j位上 */
for ( i = 0; i < len1; i++){
for ( j = 0; j < len2; j++){
res[i + j ] += ( num1[i] - '0' ) * ( num2[j] - '0' );
}
}
/* 考虑进位,与本位 ,先算进位,然后才是本位*/
for( k = 0; k < len1 + len2; k++ )
{
if( res[k] >= 10 )
{
res[k+1] += res[k] / 10;
res[k] %= 10;
}
}
char resStr[len1+len2];
for( k = 0; k < len1 + len2; k++ )
{
char c = '0' + res[k];
resStr[k]= c;
}
return resStr;
}
求高精度幂
http://poj.org/problem?id=1001
这道题在上题的引申
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 5
int main()
{
int count,n,point,i,j,k,mul[6],mul1[200],mul2[200];
char digit[10],num[10];
while(scanf("%s%d",digit,&n)!=EOF){
count=0;memset(mul1,0,sizeof(mul1));
for(i=MAX;i>=0;i--)
if(digit[i]!='0')break;
for(j=i;j>=0;j--)
if(digit[j]=='.')point=i-j;/*求小数点*/
else if(digit[j]>='0'&&digit[j]<='9'){/*除去小数点*/
mul[count]=digit[j]-'0';
mul1[count++]=digit[j]-'0';
}
/*上面预存了一次 ,循环从1 开始*/
for(i=1;i<n;i++)
{
memset(mul2,0,sizeof(mul2));
for(j=0;j<200;j++)
for(k=0;k<count;k++)
mul2[j+k]+=mul1[j]*mul[k];
/* 进位 */
for(j=0;j<200;j++)
{
if(mul2[j]>=10)
{
mul2[j+1]+=mul2[j]/10;
mul2[j]%=10;
}
}
/* 结果 存到 mul1 */
for(j=0;j<200;j++)
mul1[j]=mul2[j];
}//end of for
for(j=199;j>=0;j--)
if(mul1[j]!=0)break;
if(j==-1)
{
puts("0");
continue;
}
/* 小数点位置 */
if(j<n*point)
{
putchar('.');
for(k=1;k<n*point-j;k++)
putchar('0');
for(k=j;k>=0;k--)
printf("%d",mul1[k]);
}
else
{
for(k=j;k>=0;k--)
{
if(k==n*point-1)putchar('.');
printf("%d",mul1[k]);
}
}
putchar('\n');
}
return 0;
}