大数

文章目录

    • 概念
    • 思路
    • 模拟算法
      • 大数相乘 AxB
      • 求高精度幂

概念

所谓大数相乘(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 
#include 
#include 

#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;
}

大数_第1张图片

你可能感兴趣的:(OJ刷题)