判断一个数是否是素数
/*
费马小定理:对于素数p和任意整数a,有ap ≡ a(mod p)(同余)。反过来,满足ap ≡ a(mod p),p也几乎一定是素数。
a^(p-1) = 1 ( mod p ) p为奇质数
x^2 (mod p ) = 1
如果a^(n-1) ≡ 1 (mod n)成立,Miller-Rabin算法不是立即找另一个a进行测试,
而是看n-1是不是偶数。如果n-1是偶数,另u=(n-1)/2,
并检查是否满足二次探测定理即a^u ≡ 1 或 a^u ≡ n - 1(mod n)。
如果p是奇素数,则 x^2 ≡ 1(mod p)的解为 x ≡ 1 或 x ≡ p - 1(mod p) 差平方展开可证
*/
#include <iostream>
#include <algorithm>
typedef long long LL ;
using namespace std ;
LL n ;
LL mp[] = {2 , 3 ,5 , 7 , 11 , 13, 17, 19 , 23 , 29 , 31 , 37 , 61} ;
LL mul( LL a , LL b ) { // 用加法跳过乘法造成的数据溢出
LL ans = 0 , tmp = a ;
for( LL i = b ; i > 0 ; i>>=1 , tmp = (tmp+tmp)%n )
if( i&1) ans = (ans+tmp)%n ;
return ans ;
}
LL qpow( LL a , LL b ) // 快速幂
{
LL ans = 1 , tmp = a ;
for( LL i = b ; i > 0 ; i >>= 1 , tmp =mul(tmp , tmp ) )
if( i&1 ) ans = mul(ans , tmp ) ;
return ans ;
}
bool MillerRabin( ) // 质数检测
{
if( n <= 2 )
if( n == 2 ) return true ;
else return false ;
LL u = n-1 ;
while ( u%2 == 0 ) u /= 2 ; // 去掉所有因子2
LL tmp = u ;
for( int i = 0 ; i < 13 && mp[i] < n ; i++ )
{
LL a = mp[i] ;
u = tmp ;
LL x = qpow(a , u) ;
while (u<n) // 不断的扩大指数
{
LL y = qpow(x , 2 ) ; // 不断的平方, y为平方后的数 , x为之前的
if( y == 1 && x != 1 && x!= n-1 ) // 二次检测 同余定理
return false ;
u = u*2 ;
x = y ;
}
if(x != 1 ) // 费马小定理 a^(n-1) ≡ 1 有可能,而不是一定,但是不满足的一定不是质数
return false ;
}
return true ;
}
int main( )
{
int t ;
cin >> t ;
while ( t-- )
{
cin >> n ;
if( MillerRabin() ) cout << "Yes" <<endl ;
else cout << "No" <<endl ;
}
return 0 ;
}