Jskad/source/org/thdl/util/javaxdelta/Primes.java
2003-06-29 15:37:35 +00:00

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
/**
* @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