大数问题

本文探讨了大数运算中数组处理思想及快速幂取模算法的应用,包括大数加减乘法处理、Miller-Rabbin素数测试算法优化等。详细介绍了两种快速幂取模算法,一种为简单的迭代法,另一种采用二分法优化时间复杂度至O(logn),并提供了相应的代码实现。
摘要由CSDN通过智能技术生成
1,思想类似于大数的加减乘法. 

数组的每个元素维护一个4位数. 类似的大数问题都可以考虑这种思想

2,实例代码:

#include<iostream>
using namespace std;

int a[10000];//保存结果
int m=0;//保存位数

void factorial(int n)
{
    memset(a,0,sizeof(a));
    a[0]=1;
    for(int i=1;i<=n;i++)
    {
        int c=0; //每次新的i,都要置零
        for(int j=0;j<=m;j++)
        {
            a[j]=a[j]*i+c;  //以四位数为单位分别与i进行相乘
            c=a[j]/10000; //四位之后的数
            a[j]=a[j]%10000; //保留前四位
        }
        if(c>0)
        {
            m++; //前进了一个四位
            a[m]=c;
        }
    }
}

int main()
{
    factorial(10);
    for(int i=m;i>=0;i--)
        cout<<a[i];
    cout<<endl;
    return 0;
}

在Miller Rabbin测试素数,就用到了快速幂取模的思想。这里总结下。
求a^b%c(这就是著名的RSA公钥的加密方法),当a,b很大时,直接求解这个问题不太可能 
算法1:利用公式a*b%c=((a%c)*b)%c,这样每一步都进行这种处理,这就解决了a^b可能太大存不下的问题,但这个算法的时间复杂度依然没有得到优化
代码如下:

[cpp]  view plain copy
  1. int modexp_simple(int a,int b,int n)       
  2.      
  3.     int ret 1;  
  4.     while (b--)  
  5.      
  6.         ret ret n;  
  7.      
  8.     return ret;  
  9.    
算法2:另一种算法利用了二分的思想,可以达到O(logn)。
可以把b按二进制展开为:b = p(n)*2^n  +  p(n-1)*2^(n-1)  +…+   p(1)*2   p(0)
其中p(i) (0<=i<=n)为 0 或 1

这样 a^b =  a^ (p(n)*2^n  +  p(n-1)*2^(n-1)  +...+  p(1)*2  +  p(0))
               =  a^(p(n)*2^n)  *  a^(p(n-1)*2^(n-1))  *...*  a^(p(1)*2)  *  a^p(0)
对于p(i)=0的情况, a^(p(i) * 2^(i-1) ) =  a^0  =  1,不用处理
我们要考虑的仅仅是p(i)=1的情况
化简:a^(2^i)  = a^(2^(i-1)  * 2) = (  a^(  p(i)  *  2^(i-1)  )  )^2
(这里很重要!!具体请参阅秦九韶算法: http://baike.baidu.com/view/1431260.htm
利用这一点,我们可以递推地算出所有的a^(2^i)
当然由算法1的结论,我们加上取模运算:
a^(2^i)%c = ( (a^(2^(i-1))%c) * a^(2^(i-1)))  %c

于是再把所有满足p(i)=1的a^(2^i)%c按照算法1乘起来再%c就是结果 即二进制扫描从最高位一直扫描到最低位

 

实例代码:递归

 

[cpp]  view plain copy
  1. //计算a^bmodn       
  2. int modexp_recursion(int a,int b,int n)       
  3.      
  4.     int 1;  
  5.   
  6.     if (b == 0)  
  7.         return 1;  
  8.   
  9.     if (b == 1)  
  10.          return a%n;  
  11.   
  12.     modexp_recursion(a, b>>1, n);  
  13.   
  14.     t*t n;  
  15.   
  16.     if (b&0x1)  
  17.          
  18.         t*a n;  
  19.      
  20.   
  21.     return t;  
  22.    


 

实例代码2:非递归优化 

[cpp]  view plain copy
  1. #include <iostream>     
  2. using namespace std;     
  3.     
  4. //计算a^bmodn     
  5. int modexp(int a,int b,int n)     
  6.     
  7.     int ret=1;     
  8.     int tmp=a;     
  9.     while(b)     
  10.         
  11.        //基数存在     
  12.        if(b&0x1) ret=ret*tmp%n;     
  13.        tmp=tmp*tmp%n;     
  14.        b>>=1;     
  15.         
  16.     return ret;     
  17.     
  18.     
  19. int main()     
  20.     
  21.     cout<<modexp(2,10,3)<<endl;     
  22.     return 0;     
  23. }    

<span style="font-size:18px;">#include<stdio.h>
#include<string.h>

int main()
{
	char a[1000+10],b[1000+10];
	int a1[1000+10]={0},b1[1000+10]={0},c[1000+10]={0};
	int i,j,k=0,n,t1,t2,max,num=1;
	scanf("%d",&n);
	while(n--)
	{
		scanf("%s%s",a,b);
		t1 = strlen(a);
		t2 = strlen(b);
		max=t1>t2?t1:t2;
		for(i=t1-1,j=0;i>=0;i--,j++)
			a1[j]=a[i]-'0';
		for(i=t2-1,j=0;i>=0;i--,j++)
			b1[j]=b[i]-'0';
		for(i=0,k=0;i<max;i++)
		{
			c[i]=(a1[i]+b1[i]+k)%10;
			k=(a1[i]+b1[i]+k)/10;
		}
		printf("Case %d:\n",num);
		printf("%s + %s = ",a,b);
		if(k>0)
			printf("%d",k);
		for(i=max-1;i>=0;i--)
			printf("%d",c[i]);
		printf("\n");
		num++;
	}
	return 0;
} </span>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值