费马小定理

费马小定理在算法中的意义

1640 年,法国业余数学家 Pierre de Fermat (通常译作“费马”)发现,如果 n 是一个质数的话,那么对于任意一个数 a , a 的 n 次方减去 a 之后都将是 n 的倍数。

例如, 7 是一个质数,于是 27 – 2 、 37 – 3 , 47 – 4 ,甚至 1007 – 100 ,统统都能被 7 整除。但 15 不是质数(它可以被分解为 3 × 5 ),于是 a15 – a 除以 15 之后就可能会出现五花八门的余数了。这个规律在数论研究中是如此基本如此重要,以至于它有一个专门的名字—— Fermat 小定理。作为一个业余数学家, Fermat 发现了很多数论中精彩的结论, Fermat “小”定理只是其中之一。
Fermat 素性测试就是一种比较常用的高效方法,它基于如下原理: Fermat 小定理对一切质数都成立。回想 Fermat 小定理的内容:如果 n 是一个质数的话,那么对于任意一个数 a , a 的 n 次方减去 a 之后都将是 n 的倍数。为了判断 209 是不是质数,我们随便选取一个 a ,比如 38 。结果发现,38209 – 38 除以 209 余 114 (稍后我们会看到,即使把 209 换成上百位的大数,利用计算机也能很快算出这个余数来),不能被 209 整除。于是, 209 肯定不是质数。我们再举一个例子。为了判断 221 是不是质数,我们随机选择 a ,比如说还是 38 吧。你会发现 38221 – 38 除以 221 正好除尽。那么, 221 是否就一定是质数了呢?麻烦就麻烦在这里:这并不能告诉我们 221 是质数,因为 Fermat 小定理毕竟只说了对一切质数都成立,但没说对其他的数成不成立。万一 221 根本就不是质数,但 a = 38 时碰巧也符合 Fermat 小定理呢?为了保险起见,我们不妨再选一个不同的 a 值。比方说,令 a = 26 ,可以算出 26221 – 26 除以 221 余 169 ,因而 221 果然并不是质数。这个例子告诉了我们,如果运气不好的话,所选的 a 值会让不是质数的数也能骗过检测,虽然这个概率其实并不大。因此,我们通常的做法便是,多选几个不同的 a ,只要有一次没通过测试,被检测的数一定不是质数,如果都通过测试了,则被检测的数很可能是质数。没错, Fermat 素性测试的效率非常高,但它是基于一定概率的,有误报的可能。如果发现某个数 n 不满足 Fermat 小定理,它一定不是质数;但如果发现某个数 n 总能通过 Fermat 小定理的检验,只能说明它有很大的几率是质数。

Fermat 素性测试真正麻烦的地方就是,居然有这么一种极其特殊的数,它不是质数,但对于任意的 a 值,它都能通过测试。这样的数叫做 Carmichael 数,最小的一个是 561 ,接下来的几个则是 1105, 1729, 2465, 2821, 6601, 8911… 虽然不多,但很致命。

虽然与本文无关,但有一点不得不提:以 Fermat 的名字命名的东西里,最著名的要数 Fermat 大定理了(其实译作“ Fermat 最终定理”更贴切)。即x^n +y ^n=z ^n 不存在有理数解。

### 关于费马小定理的 C++ 编程练习 #### 使用费马小定理验证素数 费马小定理指出如果 \( p \) 是一个质数,那么对于任何整数 \( a \),\( a^p-a \) 将能被 \( p \) 整除。换句话说,当 \( p \) 不是 \( a \) 的因子时,则有 \( a^{(p-1)}\equiv 1 (\text{mod}\,p) \)[^1]。 下面是一个简单的程序来测试给定的数字是否可能是素数: ```cpp #include <iostream> using namespace std; bool modularExponentiation(int base, int exp, int modulus){ long result = 1; while (exp > 0){ if (exp % 2 == 1){ // If exponent is odd. result = (result * base) % modulus; } base = (base * base) % modulus; // Square the base and halve the exponent. exp /= 2; } return result == 1; } // Function to check primality using Fermat's Little Theorem bool fermatPrimalityTest(int n, int iterations=5){ if(n<=1 || n==4)return false; if(n<=3)return true; for(int i=0;i<iterations;++i){ int a=rand()%(n-3)+2; if(!modularExponentiation(a,n-1,n)){ return false; } } return true; } int main(){ cout << "Enter number to test: "; int num; cin >> num; if(fermatPrimalityTest(num)) cout<<num<<" might be prime."<<endl; else cout<<num<<" is not prime."<<endl; return 0; } ``` 这段代码实现了基于费马小定理的概率性素数检测算法[^2]。 #### 计算模逆元 另一个常见的应用是在计算两个大数之间的乘法逆元时使用该理论。这里提供了一个函数用于找到 `a` 对于模块 `m` 的乘法逆元(假设它们互质),即求解满足条件 \( ax ≡ 1(\text{mod} m)\) 中未知量 \( x \): ```cpp long multiplicativeInverse(long a,long phiN){ return modularExponentiation(a,phiN-1,phiN); } ``` 此方法利用了欧拉定理的一个特例——费马小定理,在已知 \( φ(m)=m−1 \) 并且 \( gcd(a,m)=1 \) 下简化了运算过程[^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值