228 lines
6.8 KiB
Java
228 lines
6.8 KiB
Java
/* Taken from the javaxdelta project. */
|
|
|
|
/*
|
|
Primes 1.1 calculates the primes 1..N, tells you if N is prime,
|
|
computes the prime just below or above N. It is useful in computing
|
|
optimal HashTable sizes. Java source included. Copyright 1998 by
|
|
Roedy Green of Canadian Mind Products. May be freely distbributed
|
|
for any purpose but military.
|
|
*/
|
|
|
|
// Primes.java
|
|
package org.thdl.util.javaxdelta;
|
|
|
|
/** Copyright 1998
|
|
* Roedy Green
|
|
* Canadian Mind Products
|
|
* #208 - 525 Ninth Street
|
|
* New Westminster, BC Canada V3M 5T9
|
|
* tel: (604) 777-1804
|
|
* 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.
|
|
*/
|
|
public class Primes
|
|
{
|
|
|
|
|
|
private static final String EmbeddedCopyright =
|
|
"Copyright 1997-2000 Roedy Green, Canadian Mind Products, http://mindprod.com";
|
|
|
|
/**
|
|
* constructors
|
|
*/
|
|
public 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.
|
|
*/
|
|
public 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
|