| // Primes.java | |
| /** Copyright 1998 | |
| * Roedy Green | |
| * Canadian Mind Products | |
| * 5317 Barker Avenue | |
| * Burnaby, BC Canada V5H 2N6 | |
| * tel: (604) 435-3016 | |
| * mailto:roedy@mindprod.com | |
| * http://mindprod.com | |
| */ | |
| // May be freely distributed for any purpose but military | |
| import java.util.BitSet; | |
| /** | |
| * @author Roedy Green | |
| * @version 1.10 1998 November 10 | |
| * Calculate primes using Eratostheses Sieve. | |
| * Tell if a given number is prime. | |
| * Find a prime just below a given number. | |
| * Find a prime just above a given number. | |
| */ | |
| /* | |
| * version 1.1 1998 November 10 - new address and phone. | |
| */ | |
| class Primes | |
| { | |
| /** | |
| * constructors | |
| */ | |
| Primes() | |
| { | |
| ensureCapacity(1000); | |
| } | |
| /** | |
| * @param capacity - largest number you will be asking if prime. | |
| * If give too small a number, it will automatically grow by | |
| * recomputing the sieve array. | |
| */ | |
| Primes (int capacity) | |
| { | |
| ensureCapacity(capacity); | |
| } | |
| /** | |
| * @param candidate - is this a prime? | |
| */ | |
| public boolean isPrime(int candidate) | |
| { | |
| ensureCapacity(candidate); | |
| if (candidate < 3) return candidate != 0; | |
| if (candidate % 2 == 0 ) return false; | |
| return !b.get(candidate/2); | |
| } | |
| /** | |
| * @return first prime higher than candidate | |
| */ | |
| public int above(int candidate) | |
| { | |
| do | |
| { | |
| // see what we can find in the existing sieve | |
| for (int i=candidate+1; i<= sieveCapacity; i++) | |
| { | |
| if (isPrime(i)) return i; | |
| } | |
| // Keep building ever bigger sieves till we succeed. | |
| // The next prime P' is between P+2 and P^2 - 2. | |
| // However that is a rather pessimistic upper bound. | |
| // Ideally some theorem would tell us how big we need to build | |
| // to find one. | |
| ensureCapacity(Math.max(candidate*2, sieveCapacity*2)); | |
| } // end do | |
| while (true); | |
| } // end above | |
| /** | |
| * @param return first prime less than candidate | |
| */ | |
| public int below (int candidate) | |
| { | |
| for (candidate--; candidate > 0; candidate--) | |
| { | |
| if (isPrime(candidate)) return candidate; | |
| } | |
| // candidate was 1 or 0 or -ve | |
| return 0; | |
| } | |
| /** | |
| * calc all primes in the range 1..n, | |
| * not the first n primes. | |
| * @param n, highest candidate, not necessarily prime. | |
| * @return list of primes 1..n in an array | |
| */ | |
| public final int[] getPrimes(int n) | |
| { | |
| // calculate the primes | |
| ensureCapacity(n); | |
| // pass 1: count primes | |
| int countPrimes = 0; | |
| for (int i = 0; i <= n; i++) | |
| { | |
| if (isPrime(i)) countPrimes++; | |
| } | |
| // pass 2: construct array of primes | |
| int [] primes = new int[countPrimes]; | |
| countPrimes = 0; | |
| for (int i = 0; i <= n; i++) | |
| { | |
| if (isPrime(i)) primes[countPrimes++] = i; | |
| } | |
| return primes; | |
| } // end getPrimes | |
| /** | |
| * calculate the sieve, bit map of all primes 0..n | |
| * @param n highest number evalutated by the sieve, not necessarily prime. | |
| */ | |
| private final void sieve ( int n ) | |
| { | |
| // Presume BitSet b set is big enough for our purposes. | |
| // Presume all even numbers are already marked composite, effectively. | |
| // Presume all odd numbers are already marked prime (0 in bit map). | |
| int last = (int)(Math.sqrt(n))+1; | |
| for (int candidate = 3; candidate <= last; candidate += 2) | |
| { | |
| // only look at odd numbers | |
| if (!b.get(candidate/2) /* if candidate is prime */) | |
| { | |
| // Our candidate is prime. | |
| // Only bother to mark multiples of primes. Others already done. | |
| // no need to mark even multiples, already done | |
| int incr = candidate*2; | |
| for ( int multiple = candidate + incr; multiple < n; multiple += incr) | |
| { | |
| b.set(multiple/2); // mark multiple as composite | |
| } // end for multiple | |
| } // end if | |
| } // end for candidate | |
| // at this point our sieve b is correct, except for 0..2 | |
| } // end sieve | |
| /** | |
| * Ensure have a sieve to tackle primes as big as n. | |
| * If we don't allocate a sieve big enough and calculate it. | |
| * @param n - ensure sieve big enough to evaluate n for primality. | |
| */ | |
| private void ensureCapacity (int n) | |
| { | |
| if ( n > sieveCapacity ) | |
| { | |
| b = new BitSet((n+1)/2); | |
| // starts out all 0, presume all numbers prime | |
| sieveCapacity = n; | |
| sieve(n); | |
| } | |
| // otherwise existing sieve is fine | |
| } // end ensureCapacity | |
| private int sieveCapacity; | |
| // biggest number we have computed in our sieve. | |
| // our BitSet array is indexed 0..N (odd only) | |
| private BitSet b; /* true for each odd number if is composite */ | |
| /** | |
| * Demonstrate and test the methods | |
| */ | |
| public static void main (String[] args) | |
| { | |
| // print primes 1..101 | |
| Primes calc = new Primes(106); | |
| int[] primes = calc.getPrimes(101); | |
| for (int i=0; i<primes.length; i++) | |
| { | |
| System.out.println(primes[i]); | |
| } | |
| // demonstrate isPrime, above, below | |
| System.out.println(calc.isPrime(149)); | |
| System.out.println(calc.below(149)); | |
| System.out.println(calc.above(149)); | |
| // print all the primes just greater than powers of 2 | |
| calc = new Primes(10000000); | |
| for (int pow=8; pow < 10000000; pow*=2) | |
| System.out.println(calc.above(pow)); | |
| // Validate that isPrime works by comparing it with brute force | |
| for (int i=3; i<=151; i++) | |
| { | |
| boolean prime = true; | |
| for (int j=2; j<i; j++) | |
| { | |
| if (i % j == 0 ) | |
| { | |
| prime = false; | |
| break; | |
| } | |
| } // end for j | |
| if ( calc.isPrime(i) != prime ) System.out.println(i + " oops"); | |
| } // end for i | |
| } // end main | |
| } // end Primes |