利用费马小定理进行素性测试

本文介绍如何利用费马小定理结合高精度算法、高精度求余和快速幂,来高效地测试一个数是否为素数。通过解决一道算法题,讨论了在大整数运算中可能出现的溢出问题以及解决方案。

利用费马小定理进行素性测试

Description

给出一个整数N,请利用费马小定理(Fermat’s Little Theorem)测试该数是否素数。
Input

多测试用例。每个测试用一行:一个正整数N ( 3 ≤ N ≤ 9223372036854775807 ,N的范围就是 long long 的范围。注意:本OJ不支持__int64这种类型,所以,如果要用 __int64类型,可直接把它改为 long long类型。__int64的输入输出用 %I64d ,long long的输入输出用%lld )
Output

每个测试用例输出一行结果:如果N是素数,输出yes,否则,输出no 。
Sample Input

127
5
67
68
Sample Output

yes
yes
yes
no

一开始的思路,只用了费马小定理的代码,递归次数太多了,如果数太大需要耗费很长时间才能计算出结果。

#include<stdio.h>
#include<stdlib.h>
#include<time.h>


//费马小定理
long long fermat(long long a,long long n,long long m)
{
    //递归出口
    if(m==0)return 1;
    else if(m==1)
        return a;
    //递归
    else{
        if(m%2==0)
            return (fermat(a,n,m/2)%n*fermat(a,n,m/2)%n)%n;
        else
            return ((fermat(a,n,m/2)%n*fermat(a,n,m/2)%n)%n*a)%n;
    }
}


int main(void)
{
    long long n,a=0;
    scanf("%lld",&n);
    while(n>=3&&n<=9223372036854775807)
    {
        srand((unsigned)time(NULL));

        //生成一个足够大的随机数(64位)
        for(int i=0;i<4;i++)
        {
            a=a+rand();
            a=a<<16;
        }
        //求n的模
        a=a%n;
        if(a<2)a=2;


        if(fermat(a,n,n-1)==1)
            printf("yes\n");
        else
            printf("no\n");
        scanf("%lld",&n);

    }
    return 0;
}

对于这道题,如果单纯只用费马小定理的话来做这道算法的话呢,理论是可以的,但是时间复杂度太高,计算一个大的数时需要很长时间,所以出现了Time Limit Exceeded。所以不得不再去研究如何去设计一种可以快速得出结果的算法。(研究了好几天还是没有头绪,最后还是去请教了一位已经AC过这道题的师兄-.-)

师兄给出了做这道题的思路,对于这道题他使用一种高效又准确的算法,通过整合费马小定理+高精度算法+高精度求余+快速幂这几个算法来实现。首先我们先来了解一下什么是费马小定理、高精度算法、高精度求余和快速幂,这几个算法也挺容易理解的。

  • 费马小定理

费马小定理(Fermat’s little theorem)是数论中的一个重要定理,在1636年提出,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p),即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

注意:可以用费马小定理判断素数,但有一定概率是错误的。费马小定理只是素数的必要条件,不是充分条件,即:满足费马小定理的数不一定是素数。
虽然有一定的概率出错,但效率高,而且也可以通过使用随机数生成a 或者增加验证费马小定理的次数来减小出错率。

  • 高精度乘法

计算机内部直接使用int和double等数据类型储存数字是有范围限制的,如:C语言的int类型与开发环境平台有关,可能是16位(2^16),也可能是32位(2^32)。当数据运算大小超过范围后,计算机将会出现溢出情况,使得计算结果不准确。当我们要计算高位数的运算时,我们可以选择高精度乘法。

高精度乘法原理:
原理是用数组或者字符串来存取数据,模拟手算进行每一位的相乘,将相乘结果按位相加,整合成一个运算结果。

#inclu
费马小定理在数论密码学中具有广泛的应用,尤其是在涉及模幂运算素性测试的场景中。以下是几个具体的应用实例: 1. **Diffie-Hellman 密钥交换协议**:费马小定理是 Diffie-Hellman 密钥交换协议的理论基础之一。在该协议中,通信双方通过公开的素数 $p$ 一个基底 $g$,各自选择一个私密的指数,然后交换计算结果。由于费马小定理指出 $a^{p-1} \equiv 1 \mod p$(当 $a$ 不被 $p$ 整除时),这保证了双方最终计算出的共享密钥是一致的,即使第三方截获了交换的信息,也难以推导出原始的私密指数[^1]。 2. **素性测试**:费马小定理可以用于设计一种概率性的素性测试方法。给定一个奇数 $n$,如果对于某个 $a$ 满足 $a^{n-1} \not\equiv 1 \mod n$,那么 $n$ 一定不是素数。虽然这种方法不是绝对可靠的(存在伪素数的情况),但它提供了一种快速排除非素数的方法。这一原理在实际的素性测试算法中被广泛应用[^1]。 3. **RSA 加密算法**:尽管 RSA 主要依赖于欧拉定理,但费马小定理为其提供了理论支持。在 RSA 中,加密解密过程涉及大素数的模幂运算。费马小定理帮助理解为什么某些特定的指数选择能够确保加密解密过程的正确性。例如,在选择公钥指数 $e$ 时,通常要求 $e$ 与 $\phi(n)$ 互素,其中 $\phi(n)$ 是欧拉函数,表示小于 $n$ 且与 $n$ 互素的正整数的个数。这一选择确保了 $e$ 存在模 $\phi(n)$ 的逆元,从而使得解密成为可能[^3]。 4. **模幂运算优化**:费马小定理还可以用于优化模幂运算。例如,在计算 $a^b \mod p$ 时,如果 $p$ 是素数,可以利用费马小定理将指数 $b$ 减少到 $b \mod (p-1)$,因为 $a^{p-1} \equiv 1 \mod p$。这种优化减少了计算的复杂度,特别是在处理大指数时非常有用[^4]。 ### 示例代码 以下是一个使用费小定理优化模幂运算的 Python 实现: ```python def mod_exp_optimized(base, exponent, modulus): # 利用费马小定理优化指数 optimized_exponent = exponent % (modulus - 1) result = 1 base = base % modulus while optimized_exponent > 0: if optimized_exponent % 2 == 1: result = (result * base) % modulus base = (base * base) % modulus optimized_exponent = optimized_exponent // 2 return result # 测试案例 a = 5 p = 7 b = 100 result = mod_exp_optimized(a, b, p) print(f"{a}^{b} ≡ {result} (mod {p})") ``` ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值