我自己的 IsPrime() 函数,基于著名的 Rabin-Miller 算法的确定性变体编写,结合优化的步进暴力破解,为您提供了最快的素数测试函数之一。
__int64 power(int a, int n, int mod)
{
__int64 power=a,result=1;
while(n)
{
if(n&1)
result=(result*power)%mod;
power=(power*power)%mod;
n>>=1;
}
return result;
}
bool witness(int a, int n)
{
int t,u,i;
__int64 prev,curr;
u=n/2;
t=1;
while(!(u&1))
{
u/=2;
++t;
}
prev=power(a,u,n);
for(i=1;i<=t;++i)
{
curr=(prev*prev)%n;
if((curr==1)&&(prev!=1)&&(prev!=n-1))
return true;
prev=curr;
}
if(curr!=1)
return true;
return false;
}
inline bool IsPrime( int number )
{
if ( ( (!(number & 1)) && number != 2 ) || (number < 2) || (number % 3 == 0 && number != 3) )
return (false);
if(number<1373653)
{
for( int k = 1; 36*k*k-12*k < number;++k)
if ( (number % (6*k+1) == 0) || (number % (6*k-1) == 0) )
return (false);
return true;
}
if(number < 9080191)
{
if(witness(31,number)) return false;
if(witness(73,number)) return false;
return true;
}
if(witness(2,number)) return false;
if(witness(7,number)) return false;
if(witness(61,number)) return false;
return true;
/*WARNING: Algorithm deterministic only for numbers < 4,759,123,141 (unsigned int's max is 4294967296)
if n < 1,373,653, it is enough to test a = 2 and 3.
if n < 9,080,191, it is enough to test a = 31 and 73.
if n < 4,759,123,141, it is enough to test a = 2, 7, and 61.
if n < 2,152,302,898,747, it is enough to test a = 2, 3, 5, 7, and 11.
if n < 3,474,749,660,383, it is enough to test a = 2, 3, 5, 7, 11, and 13.
if n < 341,550,071,728,321, it is enough to test a = 2, 3, 5, 7, 11, 13, and 17.*/
}
要使用,请将代码复制并粘贴到程序顶部。调用它,它会返回一个 BOOL 值,true 或 false。
if(IsPrime(number))
{
cout << "It's prime";
}
else
{
cout<<"It's composite";
}
如果您在使用“__int64”进行编译时遇到问题,请将其替换为“long”。在VS2008和VS2010下都能正常编译。
它是如何工作的:
该函数分为三个部分。部分检查是否是罕见的异常之一(负数,1),并拦截程序的运行。
如果数字小于 1373653,则第二部分开始,这是理论上 Rabin Miller 算法将击败我优化的蛮力函数的数字。然后是两个级别的 Rabin Miller,旨在最大限度地减少所需的证人数量。由于您将要测试的大多数数字都低于 40 亿,因此概率 Rabin-Miller 算法可以通过检查证人 2、7 和 61 来确定。如果您需要超过 40 亿上限,您将需要一个大的number 库,并对 power() 函数应用模数或位移修改。
如果你坚持使用暴力破解方法,这里只是我优化的暴力破解 IsPrime() 函数:
inline bool IsPrime( int number )
{
if ( ( (!(number & 1)) && number != 2 ) || (number < 2) || (number % 3 == 0 && number != 3) )
return (false);
for( int k = 1; 36*k*k-12*k < number;++k)
if ( (number % (6*k+1) == 0) || (number % (6*k-1) == 0) )
return (false);
return true;
}
}
这个蛮力作品的工作原理:
所有素数(除了 2 和 3)都可以用 6k+1 或 6k-1 的形式表示,其中 k 是正整数。这段代码使用了这个事实,并以 6k+1 或 6k-1 的形式测试所有数字,小于所讨论数字的平方根。这块集成到我更大的 IsPrime() 函数中(首先显示的函数)。
如果你需要找出一个数之下的所有素数,找出所有低于 1000 的素数,看看埃拉托色尼筛法。我的另一个最爱。
作为补充说明,我希望看到有人实现椭圆曲线方法算法,一直想看到用 C++ 实现该算法有一段时间了,但我失去了它的实现。从理论上讲,它甚至比我实现的确定性 Rabin Miller 算法还要快,尽管我不确定这是否适用于 40 亿以下的数字。