Currently I have this prime generator that is limited to n < 2^32-1. I'm not entirely sure how I could expand the limit further, given the limit of elements in an array.
Sieve:
public class Main {
public static void main(String args[]){
long N = 2000000000;
// initially assume all integers are prime
boolean[] isPrime = new boolean[N + 1];
for (int i = 2; i <= N; i++) {
isPrime[i] = true;
}
// mark non-primes <= N using Sieve of Eratosthenes
for (int i = 2; i*i <= N; i++) {
// if i is prime, then mark multiples of i as nonprime
// suffices to consider mutiples i, i+1, ..., N/i
if (isPrime[i]) {
for (int j = i; i*j <= N; j++) {
isPrime[i*j] = false;
}
}
}
}
}
How could I modify this to go past n = 2^32-1?
You may use an array of BitSet
objects to represent long bit-set. Here's the complete example:
public class Main {
private static class LongBitSet {
// max value stored in single BitSet
private static final int BITSET_SIZE = 1 << 30;
BitSet[] bitsets;
public LongBitSet(long limit) {
bitsets = new BitSet[(int) (limit/BITSET_SIZE+1)];
// set all bits by default
for(int i=0; i<bitsets.length; i++) {
bitsets[i] = new BitSet();
int max = (int) (i == bitsets.length-1 ?
limit % BITSET_SIZE : BITSET_SIZE);
bitsets[i].set(0, max);
}
}
// clear specified bit
public void clear(long pos) {
bitsets[(int) (pos / BITSET_SIZE)].clear((int) (pos % BITSET_SIZE));
}
// get the value of the specified bit
public boolean get(long pos) {
return bitsets[(int) (pos / BITSET_SIZE)].get((int) (pos % BITSET_SIZE));
}
// get the number of set bits
public long cardinality() {
long cardinality = 0;
for(BitSet bs : bitsets) {
cardinality += bs.cardinality();
}
return cardinality;
}
}
public static void main(String args[]) {
long N = 4000000000L;
// initially assume all integers are prime
LongBitSet bs = new LongBitSet(N+1);
// clear 0 and 1: non-primes
bs.clear(0);
bs.clear(1);
// mark non-primes <= N using Sieve of Eratosthenes
for (long i = 2; i * i <= N; i++) {
if (bs.get(i)) {
for (long j = i; i * j <= N; j++) {
bs.clear(i * j);
}
}
}
System.out.println(bs.cardinality());
}
}
This program for N = 4_000_000_000L
takes around 512Mb of memory, works couple of minutes and prints 189961812
which is correct number of primes below 4 billions according to Wolfram Alpha. If you have enough RAM, you may try setting even bigger N.
You can segment the sieve: instead of allocating a single, gigantic array you allocate many small arrays. If you want to find the primes up to 10^10 you might use arrays (or better yet, BitSet
s) of size 10^6 or so. Then you run the sieve 10^4 times. Each time you run a new segment you need to find out where to start each prime in the sieve, but that's not really too hard.
In addition to allowing much smaller memory use this keeps more of the memory in the cache, so it's often significantly faster.
I see options:
pack 16 numbers / 1 BYTE
use more than 1 table
you can use more approaches at once
to spare memory you can combine 16/32/64 bit variables
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With