Java 在一个非常大的给定整数范围内寻找所有素数的程序
我在一个编程网站上遇到了以下问题: 彼得想为他的密码系统生成一些素数。救救他!您的任务是生成两个给定数字之间的所有素数 输入Java 在一个非常大的给定整数范围内寻找所有素数的程序,java,algorithm,primes,sieve-of-eratosthenes,Java,Algorithm,Primes,Sieve Of Eratosthenes,我在一个编程网站上遇到了以下问题: 彼得想为他的密码系统生成一些素数。救救他!您的任务是生成两个给定数字之间的所有素数 输入 输入以单行中的测试用例数t开始(t使用位集而不是布尔值数组) public static BitSet primes (final int MAX) { BitSet primes = new BitSet (MAX); // make only odd numbers candidates... for (int i = 3; i <
输入以单行中的测试用例数t开始(t使用位集而不是布尔值数组)
public static BitSet primes (final int MAX)
{
BitSet primes = new BitSet (MAX);
// make only odd numbers candidates...
for (int i = 3; i < MAX; i+=2)
{
primes.set(i);
}
// ... except no. 2
primes.set (2, true);
for (int i = 3; i < MAX; i+=2)
{
/*
If a number z is already eliminated (like 9),
because it is itself a multiple of a prime
(example: 3), then all multiples of z (9) are
already eliminated.
*/
if (primes.get (i))
{
int j = 3 * i;
while (j < MAX)
{
if (primes.get (j))
primes.set (j, false);
j += (2 * i);
}
}
}
return primes;
}
公共静态位集素数(最终int MAX)
{
位集素数=新位集(最大值);
//只做奇数。。。
对于(int i=3;i
您是否有将结果存储在数组中?如何使用一种方法来计算给定整数是否为素数,只为{left,left+1,…,right}
中的每个数字调用它?在访问isNotPrime数组时,始终可以使用偏移量
给定m,n:
boolean[] isNotPrime = new boolean[n-m+1];
// to now if number x is primer or not
boolean xIsPrime = isNotPrime[x-m];
这里m是偏移量。您不必拥有一个大数组:您可以保留一个到目前为止找到的素数列表,并使用多个数组进行测试,其值=数组\u插槽+偏移量(已测试的值)。完成从i到j的值后,将j-i添加到偏移量,并从j开始启动一个新数组 您可以从数组中删除偶数,这样可以节省一些空间(value=array\u slot*2-1)。
1由于m和n之间的距离相对较小,因此可以对m和n之间的每个数字使用蛮力和快速素性测试算法
如果你允许概率算法,你可以使用。让M=n-M 100000000/32整数元素数组..这还会有很多空间吗?我们有没有办法利用n-M是1/32 GB的限制,不是吗?价格大约:半美元。我会在时间里看到一个问题,需要填充这个位集。但是,我不知道如何解决e Eulers totient解决了这个问题,但在100000的时间间隔内看不到任何帮助。我不希望probablePrime方法被允许。我还没有初始化isNotPrime表,因为我打算将其默认值设置为false。另外,您建议的方法在时间上会非常昂贵,这就是为什么我没有使用它t、 在分离中测试每个候选数的素数(通过试算法?)比使用埃拉托斯烯的偏移筛一次性在整个范围内标记合成物要慢得多(当然,对于低于上限的
sqrt
的每个素数)。如果从3开始,而不是从筛选中的2开始,并设法在循环外将值交换为2,则可以通过i+=2;进行迭代。然后,不再在外部循环中运行isNotPrime.length,√(isNotPrime.length)
应该足够了。无关:Scanner有一个方法nextInt。你可以通过循环范围内的赔率,从奇数开始,在中增加i+=2
for(int i=0;i
。确保i
对应的奇数不低于左
。2以上的偶数永远不会成为素数。:)这将是稀疏寻址方案,使用压缩数组更快,其中索引i
处的条目表示数字n=left\u odd+2i
。在Sieve()。看看丹尼尔的答案。我已经根据你的建议编辑了我的解决方案,但仍然超出了时间限制。您能建议如何进一步优化吗?时间限制是什么?任务是什么?如果要打印出所有的素数,这可能就是瓶颈。我对Java的I/O不是很精通,所以我无法提供如何加快打印速度的建议。如果您只打印每个间隔中素数的数量(或总和),那么这应该不是一个问题。这个实现进行设置并筛选100个大约100000长度的间隔,在90毫秒以下,JVM的启动时间更高。当然,测试机器可能速度较慢,缓存较小,因此用位集
s替换布尔[]
可能会更好。
boolean[] isNotPrime = new boolean[n-m+1];
// to now if number x is primer or not
boolean xIsPrime = isNotPrime[x-m];
public int[] chunk(int m, int n) {
if (n < 2) return null;
if (m < 2) m = 2;
if (n < m) throw new IllegalArgumentException("Borked");
int root = (int)Math.sqrt((double)n);
boolean[] sieve = new boolean[n-m+1];
// primes is the global array of primes to 31621 populated earlier
// primeCount is the number of primes stored in primes, i.e. 3401
// We ignore even numbers, but keep them in the sieve to avoid index arithmetic.
// It would be very simple to omit them, though.
for(int i = 1, p = primes[1]; i < primeCount; ++i) {
if ((p = primes[i]) > root) break;
int mult;
if (p*p < m) {
mult = (m-1)/p+1;
if (mult % 2 == 0) ++mult;
mult = p*mult;
} else {
mult = p*p;
}
for(; mult <= n; mult += 2*p) {
sieve[mult-m] = true;
}
}
int count = m == 2 ? 1 : 0;
for(int i = 1 - m%2; i < n-m; i += 2) {
if (!sieve[i]) ++count;
}
int sievedPrimes[] = new int[count];
int pi = 0;
if (m == 2) {
sievedPrimes[0] = 2;
pi = 1;
}
for(int i = 1 - m%2; i < n-m; i += 2) {
if (!sieve[i]) {
sievedPrimes[pi++] = m+i;
}
}
return sievedPrimes;
}