我已编写此代码以检查数字是否为素数(对于数字最多为10 ^ 9 + 7)
这是一个好方法吗?我所做的是我制作了unordered_set
,将素数存储到sqrt(n)
。
在检查数字是否为素数时,如果首先检查它是否小于表中的最大数量
如果它更少,则在表格中搜索,因此在这种情况下复杂性应为O(1)
如果它是更多的数字是通过一个可分性测试与包含素数的数字集中的数字。
#include<iostream>
#include<set>
#include<math.h>
#include<unordered_set>
#define sqrt10e9 31623
using namespace std;
unordered_set<long long> primeSet = { 2, 3 }; //used for fast lookups
void genrate_prime_set(long range) //this generates prime number upto sqrt(10^9+7)
{
bool flag;
set<long long> tempPrimeSet = { 2, 3 }; //a temporay set is used for genration
set<long long>::iterator j;
for (int i = 3; i <= range; i = i + 2)
{
//cout << i << " ";
flag = true;
for (j = tempPrimeSet.begin(); *j * *j <= i; ++j)
{
if (i % (*j) == 0)
{
flag = false;
break;
}
}
if (flag)
{
primeSet.insert(i);
tempPrimeSet.insert(i);
}
}
}
bool is_prime(long long i,unordered_set<long long> primeSet)
{
bool flag = true;
if(i <= sqrt10e9) //if number exist in the lookup table
return primeSet.count(i);
//if it doesn't iterate through the table
for (unordered_set<long long>::iterator j = primeSet.begin(); j != primeSet.end(); ++j)
{
if (*j * *j <= i && i % (*j) == 0)
{
flag = false;
break;
}
}
return flag;
}
int main()
{
//long long testCases, a, b, kiwiCount;
bool primeFlag = true;
//unordered_set<int> primeNum;
genrate_prime_set(sqrt10e9);
cout << primeSet.size()<<"\n";
cout << is_prime(9999991,primeSet);
return 0;
}
答案 0 :(得分:1)
这并不是一种特别有效的方式来完成手头工作。
虽然它最终可能不会产生很大的不同,但是生成所有质数达到某个特定极限的有效方法显然是使用筛子 - Eratosthenes的筛子简单而快速。有一些修改可以更快,但对于你正在处理的小尺寸,它们可能不值得。
这些通常以比您目前使用的更有效的格式生成其输出。特别是,你通常只将一个位专用于每个可能的素数(即每个奇数),如果数字为复合则最终为零;如果是素数,则为一个(当然,如果您愿意,可以反转意义) )。
由于每个奇数从3到31623只需要一位,所以这只需要大约16 K位,或大约2K字节 - 按现代标准来说,这是一个真正微不足道的内存量(特别是:足够小以适应L1缓存很容易)。
由于这些位按顺序存储,因此根据您测试的数字的平方根计算和测试而不是测试表中的所有数字(包括大于正方形的数字)也是微不足道的你正在测试的数字的根,这显然是浪费时间)。这也优化了对内存的访问,以防一些内存不在缓存中(即,您可以按顺序访问所有数据,使硬件预取器的生活尽可能简单。)
如果你想进一步优化,我会考虑使用筛子找到最多10个 9 +7的所有质数,并查找输入。这是否胜利将(严重)取决于您可以接收的查询数量。快速检查表明,Eratosthenes筛子的简单实施可以在大约17秒内找到所有素数高达10 9 。在那之后,每个查询(当然)基本上是瞬时的(即,单个存储器读取的成本)。对于筛子的结果,这确实需要大约120兆字节的内存,这曾经是主要的考虑因素,但是(除了在相当有限的系统上)通常不会再有了。
答案 1 :(得分:1)
答案非常简短:从“Miller-Rabin”一词开始研究这个问题
简短的回答是否定的:
另外,如果真的需要参数,你应该通过引用接收primeSet
而不是复制。
注意:测试小素数以查看它们是否除数是素数测试的一个有用的第一步,但通常应该只用于最小的素数然后切换到更好的素数方法子>
答案 2 :(得分:1)
不,这不是确定数字是否为素数的好方法。这是一个简单素数测试的伪代码,足以满足你范围内的数字;我会留给你翻译成C ++:
function isPrime(n)
d := 2
while d * d <= n
if n % d == 0
return False
d := d + 1
return True
这可以通过尝试每个可能的除数直到输入数 n 的平方根;如果没有找到除数,则输入数字不能是复合的,意味着形式 n = p × q ,因为其中一个两个除数 p 或 q 必须小于 n 的平方根,而另一个除数大于 n的平方根
有更好的方法来确定素数;例如,在最初检查数字是否为偶数(因此仅在 n = 2时为素数)之后,只需要测试奇数潜在除数,将所需的工作量减半。如果您有一个素数列表,直到 n 的平方根,您可以将该列表用作试验除数,并使该过程更快。还有其他技术可以用于更大的 n 。
但这应该足以让你开始。如果您准备好了更多,请回到这里并提出更多问题。
答案 3 :(得分:0)
我只能建议一种在Java中使用库函数来检查数字的素数的方法。至于其他问题,我没有任何答案。
java.math.BigInteger.isProbablePrime(int certainty)如果此BigInteger可能是素数则返回true,如果它肯定是复合则返回false。如果确定性≤0,则返回true。您应该尝试在代码中使用它。所以尝试用Java重写它
确定性 - 调用者愿意容忍的不确定性的度量:如果调用返回true,则此BigInteger为素数的概率超过(1 - 1/2 ^确定性)。此方法的执行时间与此参数的值成比例。
如果此BigInteger可能是素数,则此方法返回true,如果它肯定是复合的,则返回false。
以下示例显示了math.BigInteger.isProbablePrime()方法的用法
import java.math.*;
public class BigIntegerDemo {
public static void main(String[] args) {
// create 3 BigInteger objects
BigInteger bi1, bi2, bi3;
// create 3 Boolean objects
Boolean b1, b2, b3;
// assign values to bi1, bi2
bi1 = new BigInteger("7");
bi2 = new BigInteger("9");
// perform isProbablePrime on bi1, bi2
b1 = bi1.isProbablePrime(1);
b2 = bi2.isProbablePrime(1);
b3 = bi2.isProbablePrime(-1);
String str1 = bi1+ " is prime with certainity 1 is " +b1;
String str2 = bi2+ " is prime with certainity 1 is " +b2;
String str3 = bi2+ " is prime with certainity -1 is " +b3;
// print b1, b2, b3 values
System.out.println( str1 );
System.out.println( str2 );
System.out.println( str3 );
}
}
7 is prime with certainity 1 is true
9 is prime with certainity 1 is false
9 is prime with certainity -1 is true