7的200次方除以19的余数是多少

欧拉定理幂取模同余反复平方法

一、用欧拉定理手算

1
欧拉方程 ϕ ( n ) \phi(n) ϕ(n)

3
欧拉定理和欧拉方程 ϕ ( n ) \phi(n) ϕ(n)可以百度或者
看我之前的博客(有点简陋)
博客1
博客2

二、利用同余的性质迭代

a b   m o d   m = a ( b   m o d   m ) m o d   m ab\ mod\ m=a(b\ mod\ m)mod\ m ab mod m=a(b mod m)mod m
简要证明:设b=km+c,则b mod m=c上式两边都等于ac mod m

通过上面的式子可以把b不断缩小

代码:

/**
 * @Title:f1
 * @Description:TODO  通过公式 ab mod m=b*(a mod m)mod m实现幂取模
 * @param x    底数
 * @param n    指数
 * @param m    除数
 * @return_type   余数
 * @return int  
 * @throws
 */
public static int f1(int x,int n,int m) {
	int ret=1;
	for(int i=0;i<n;++i)
		ret=(ret*x)%m;   
	return ret;
}

三、反复平方法

  • x n 可 以 表 示 成 x a 0 2 0 × x a 1 2 1 × x a 2 2 2 × ⋅ ⋅ ⋅ × x a k 2 k x^n可以表示成x^{a_02^0}\times x^{a_12^1}\times x^{a_22^2}\times\cdot\cdot\cdot\times x^{a_k2^k} xnxa020×xa121×xa222××xak2k
    其中 { a i = 0 或 1   ∣   i = 0 , 1 , 2 , . . . , k } \{a_i=0或1\ |\ i=0,1,2,...,k\} {ai=01  i=0,1,2,...,k}即把n换成二进制的形式。
    然后计算 x n   m o d   m x^n\ mod\ m xn mod m可以通过分别计算上面k个数除以m的余数的乘积再除以m(由带余除法可以简单推出)
  • 又因为 x 2 i + 1 = ( x 2 i ) 2 x^{2^{i+1}}=(x^{2^i})^2 x2i+1=(x2i)2
    由第二点的 a b   m o d   m = a ( b   m o d   m ) m o d   m ab\ mod\ m=a(b\ mod\ m)mod\ m ab mod m=a(b mod m)mod m
    可知第i+1项除以m的余数可以由第i项除以m的余数推出,这是什么意思呢?(先不管,把 a i 当 1 看 a_i当1看 ai1)比如 第i项是6,它除以4的余数是2,那么第i+1项是36,它除以4的余数可以由(2*2)mod 4得到,即0
  • 知道这些就可以写代码了,如下:
    (代码先把每一项 x 1 ⋅ 2 i x^{1\cdot2^i} x12i除以m的余数算出来,然后当 a i a_i ai等于1时,就把余数记录下来,不等于1余数是1不需要记录。记录下来的余数按照第二点里的迭代方法,即这些余数相乘的结果除以m就是最终的答案)
/**
 * @Title:f2
 * @Description:TODO  反复平方法实现幂取模
 * @param x    底数
 * @param n    指数
 * @param m    除数
 * @return_type   int
 * @return 余数  
 * @throws
 */
public static int f2(int x,int n, int m) {
	int ret=1;
	/*prev记录当前循环的前一位除以m的余数,
	 * 比如n=01001,当执行到第三个0时,它的前一位是0,
	 * prev就是x^2除以m的余数(第二个0对应的二进制是第三位)*/
	int prev=x;
	while(n>0) {
		if((n&1)==1) {  //当前位为1
			/*思路同f1()方法,ret记录了n的位数到目前为止
			 * 除以m的余数,比如n是01011001,假设现在到了1001,
			 * 那就是(二进制)x^(1001)除以m的余数*/
			ret=(ret*prev)%m;   
		}
		prev=(prev*prev)%m;
		n>>=1;
	}
	return ret;
}

四、欧拉方法的代码

/**
 * @Title:numOfprimes
 * @Description:TODO  计算小于n且与n互质的正整数的个数
 * @param n   
 * @return   个数
 * @return_type int  
 * @throws
 */
public static int numOfprimes(int n) {
	double ret=n*1.0;
	ArrayList<Integer>p = new ArrayList<Integer>(n/2);
	int num=0;
	for(int i=2;i*i<=n;++i) {
		if((n&(i-1))==0) {  //n % i==0
		p.add(i);
		while(n/i==0)
			n/=i;
		}
		}
	if(n>1)
		p.add(n);
	for(int i=0;i<p.size();++i)
		ret=ret*(1-1.0/p.get(i));
	return (int)ret;
}

/**
 * @Title:f3
 * @Description:TODO  运用欧拉公式
 * @param x    底数
 * @param n    指数
 * @param m    除数
 * @return_type   int
 * @return 余数
 * @throws
 */
public static int f3(int x,int n,int m) {
	int num=numOfprimes(m);
	if(num<=0)
		return -1;
	int count=n%num;
	return f1(x,count,m);
}

五、完整代码

package modofpower;

import java.util.ArrayList;

/**
 * @author 乃乃天外仙
 *
 */
public class mod_power {
	
/**
 * @Title:f1
 * @Description:TODO  通过公式 ab mod m=b*(a mod m)mod m实现幂取模
 * @param x    底数
 * @param n    指数
 * @param m    除数
 * @return_type   余数
 * @return int  
 * @throws
 */
public static int f1(int x,int n,int m) {
	int ret=1;
	for(int i=0;i<n;++i)
		ret=(ret*x)%m;   
	return ret;
}


/**
 * @Title:f2
 * @Description:TODO  反复平方法实现幂取模
 * @param x    底数
 * @param n    指数
 * @param m    除数
 * @return_type   int
 * @return 余数  
 * @throws
 */
public static int f2(int x,int n, int m) {
	int ret=1;
	/*prev记录当前循环的前一位除以m的余数,
	 * 比如n=01001,当执行到第三个0时,它的前一位是0,
	 * prev就是x^2除以m的余数(第二个0对应的二进制是第三位)*/
	int prev=x;
	while(n>0) {
		if((n&1)==1) {  //当前位为1
			/*思路同f1()方法,ret记录了n的位数到目前为止
			 * 除以m的余数,比如n是01011001,假设现在到了1001,
			 * 那就是(二进制)x^(1001)除以m的余数*/
			ret=(ret*prev)%m;   
		}
		prev=(prev*prev)%m;
		n>>=1;
	}
	return ret;
}

/**
 * @Title:numOfprimes
 * @Description:TODO  计算小于n且与n互质的正整数的个数
 * @param n   
 * @return   个数
 * @return_type int  
 * @throws
 */
public static int numOfprimes(int n) {
	double ret=n*1.0;
	ArrayList<Integer>p = new ArrayList<Integer>(n/2);
	int num=0;
	for(int i=2;i*i<=n;++i) {
		if((n&(i-1))==0) {  //n % i==0
		p.add(i);
		while(n/i==0)
			n/=i;
		}
		}
	if(n>1)
		p.add(n);
	for(int i=0;i<p.size();++i)
		ret=ret*(1-1.0/p.get(i));
	return (int)ret;
}

/**
 * @Title:f3
 * @Description:TODO  运用欧拉公式
 * @param x    底数
 * @param n    指数
 * @param m    除数
 * @return_type   int
 * @return 余数
 * @throws
 */
public static int f3(int x,int n,int m) {
	int num=numOfprimes(m);
	if(num<=0)
		return -1;
	int count=n%num;
	return f2(x,count,m);
}

public static void main(String[]args) {
	System.out.println("f1()方法结果:"+f1(7,200,19));
	System.out.println("f2()方法结果:"+f2(7,200,19));
	System.out.println("f3()方法结果:"+f3(7,200,19));
}
}

输出结果:
2

六、时间复杂度

利用同余性质迭代的算法的时间复杂度是 O ( n ) O(n) O(n)(n是指数)
反复平方法的时间复杂度是 O ( l o g 2 n ) O(log_2n) O(log2n)(n是指数)
欧拉方法的时间复杂度是 O ( m 1 2 ) O(m^{1\over2}) O(m21)(m是底数),因为计算小于m且与m互质的正整数个数需要 O ( m 1 2 ) O(m^{1\over2}) O(m21)的时间,之后调用f2()的时间只需要 O ( l o g 2 m ) O(log_2m) O(log2m),所以总的时间复杂度是 O ( m 1 2 ) O(m^{1\over2}) O(m21)

七、Reference

1.A Concise Introduction to the Theory of Numbers- Baker A第二章

2.幂取模算法:https://blog.csdn.net/chen77716/article/details/7093600

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值