大数

概念

所谓大数相乘(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;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lin_AIOS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值