Modification of sieve of eratosthenes, time and space complexity check - java

I understand the time complexity for the 'sieve of eratosthenes' algorithm to be O(n log log n). I have modified this algorithm such that my sieve will always be of size 100. I will keep looping over next 100 numbers if I do not find the next prime. How would I explain the time-complexity And Space complexity of getNthPrime and getNextPrime methods ?
A snippet:
public class PrimeUtil {
private static final boolean COMPOSITE = true;
private static final int DEFAULT_SIZE = 100;
// cache of primes.
public final List<Integer> primes;
public int cachedMaxPrime;
public PrimeUtil() {
primes = new ArrayList<Integer>();
// initial seed
primes.addAll(Arrays.asList(2, 3, 5, 7, 11, 13));
cachedMaxPrime = primes.get(primes.size() - 1);
}
private void validate(int n) {
if (n <= 0) {
throw new IllegalArgumentException("Expecting a non-zero value");
}
}
public synchronized int getNthPrime(int nThPrime) {
validate(nThPrime);
if (nThPrime <= primes.size()) {
return primes.get(nThPrime - 1);
}
int n = DEFAULT_SIZE; // find all primes for next 100 numbers.
while (primes.size() < nThPrime) {
computePrimesUptoN(n);
n += DEFAULT_SIZE; // find all primts for next 100 numbers.
}
return primes.get(nThPrime - 1);
}
public synchronized int getNextPrime(int prime) {
validate(prime);
int primeIndex = Collections.binarySearch(primes, prime);
if (primeIndex != -1 && primeIndex != (primes.size() - 1)) {
return primes.get(primeIndex + 1);
}
int prevSize = primes.size();
int n = DEFAULT_SIZE; // adding cachedMaxPrime to DEFAULT_SIZE is a tiny optimization, nothing else.
while (primes.size() == prevSize) {
computePrimesUptoN(n);
n += DEFAULT_SIZE;
}
return primes.get(primeIndex + 1);
}
private List<Integer> computePrimesUptoN(int n) {
boolean[] composites = new boolean[n - cachedMaxPrime]; //
int root = (int)Math.sqrt(n); // root is sqrt(50) ie 7.
for (int i = 1; i < primes.size() && primes.get(i) <= root; i++) { // will loop until prime = 7.
int prime = primes.get(i); // first prime: 3
int firstPrimeMultiple = (cachedMaxPrime + prime) - ((cachedMaxPrime + prime) % prime);
if (firstPrimeMultiple % 2 == 0) {
firstPrimeMultiple += prime;
}
filterComposites(composites, prime, firstPrimeMultiple, n);
}
// loop through all primes in the range of max-cached-primes upto root.
for (int prime = cachedMaxPrime + 2; prime < root; prime = prime + 2) {
if (!composites[prime]) {
// selecting all the prime numbers.
filterComposites(composites, prime, prime, n);
}
}
for (int i = 1; i < composites.length; i = i + 2) {
if (!composites[i]) {
primes.add(i + (cachedMaxPrime + 1));
}
}
cachedMaxPrime = primes.get(primes.size() - 1);
return primes;
}
private void filterComposites(boolean[] composites, int prime, int firstMultiple, int n) {
for (int multiple = firstMultiple; multiple < n; multiple += prime + prime) {
composites[multiple - (cachedMaxPrime + 1)] = COMPOSITE;
}
}
}

Related

How to encode a number using its prime factors in java using arrays?

I have this question I am trying to solve
I wrote this code
public static int[] encodeNumber(int n) {
int count = 0, base = n, mul = 1;
for (int i = 2; i < n; i++) {
if(n % i == 0 && isPrime(i)) {
mul *= i;
count++;
if(mul == n) {
break;
}
n /= i;
}
}
System.out.println("count is " + count);
int[] x = new int[count];
int j = 0;
for (int i = 2; i < base; i++) {
if(n % i == 0 && isPrime(i)) {
mul *= i;
x[j] = i;
j++;
if(mul == n) break;
n /= i;
}
break;
}
return x;
}
public static boolean isPrime(int n) {
if(n < 2) return false;
for (int i = 2; i < n; i++) {
if(n % i == 0) return false;
}
return true;
}
I am trying to get the number of its prime factors in a count variable and create an array with the count and then populate the array with its prime factors in the second loop.
count is 3
[2, 0, 0]
with an input of 6936. The desired output is an array containing all its prime factors {2, 2, 2, 3, 17, 17}.
Your count is wrong, because you count multiple factors like 2 and 17 of 6936 only once.
I would recommend doing it similar to the following way, recursively:
(this code is untested)
void encodeNumberRecursive(int remainder, int factor, int currentIndex, Vector<Integer> results) {
if(remainder<2) {
return;
}
if(remainder % factor == 0) {
results.push(factor);
remainder /= factor;
currentIndex += 1;
encodeNumberRecursive(remainder , factor, currentIndex, results);
} else {
do {
factor += 1;
} while(factor<remainder && !isPrime(factor));
if(factor<=remainder) {
encodeNumberRecursive(remainder , factor, currentIndex, results);
}
}
}
Finally, call it with
Vector<Integer> results = new Vector<Integer>();
encodeNumberRecursive(n, 2, 0, results);
You can also do it without recursion, I just feel it is easier.
Well here is a piece of code I would start with. It is not finished yet and I did not test it, but that's the way you should go basically.
// First find the number of prime factors
int factorsCount = 0;
int originalN = n;
while (n > 1) {
int p = findLowestPrimeFactor(n);
n /= p;
factorsCount++;
}
// Now create the Array of the appropriate size
int[] factors = new int[factorsCount];
// Finally do the iteration from the first step again, but now filling the array.
n = originalN;
int k = 0;
while (n > 1) {
int p = findLowestPrimeFactor(n);
factors[k] = p;
k++;
n = n / p;
}
return factors;
Having found a factor (on increasing candidates), you can assume it is prime,
if you divide out the factor till the candidate no longer is a factor.
Your problem is not repeatedly dividing by the factor.
public static int[] encodeNumber(int n) {
if (n <= 1) {
return null;
}
List<Integer> factors = new ArrayList<>();
for (int i = 2; n != 1; i += 1 + (i&1)) {
while (n % i == 0) { // i is automatically prime, as lower primes done.
factors.add(i);
n /= i;
}
}
return factors.stream().mapToInt(Integer::intValue).toArray();
}
Without data structures, taking twice the time:
public static int[] encodeNumber(int n) {
if (n <= 1) {
return null;
}
// Count factors, not storing them:
int factorCount = 0;
int originalN = n;
for (int i = 2; n != 1; i += 1 + (i&1)) {
while (n % i == 0) {
++factorCount;
n /= i;
}
}
// Fill factors:
n = originalN;
int[] factors = new int[factorCount];
factorCount = 0;
for (int i = 2; n != 1; i += 1 + (i&1)) {
while (n % i == 0) {
factors[factorCount++] = i;
n /= i;
}
}
return factors;
}

Finding the smith number between given range

I will get to the point quickly. Basically smith numbers are: Composite number the sum of whose digits is the sum of the digits of its prime factors (excluding 1). (The primes are excluded since they trivially satisfy this condition). One example of a Smith number is the beast number 666=2·3·3·37, since 6+6+6=2+3+3+(3+7)=18.
what i've tried:
In a for loop first i get the sum of the current number's(i) digits
In same loop i try to get the sum of the number's prime factors digits.
I've made another method to check if current number that is going to proccessed in for loop is prime or not,if its prime it will be excluded
But my code is seems to not working can you guys help out?
public static void main(String[] args) {
smithInrange(1, 50);
}
public static void smithInrange(int start_val, int end_val) {
for (int i = start_val; i < end_val; i++) {
if(!isPrime(i)) { //since we banned prime numbers from this process i don't include them
int for_digit_sum = i, digit = 0, digit_sum = 0, for_factor_purpose = i, smith_sum = 0;
int first = 0, second = 0, last = 0;
// System.out.println("current number is" + i);
while (for_digit_sum > 0) { // in this while loop i get the sum of current number's digits
digit = for_digit_sum % 10;
digit_sum += digit;
for_digit_sum /= 10;
}
// System.out.println("digit sum is"+digit_sum);
while (for_factor_purpose % 2 == 0) { // i divide the current number to 2 until it became an odd number
first += 2;
for_factor_purpose /= 2;
}
// System.out.println("the first sum is " + first);
for (int j = 3; j < Math.sqrt(for_factor_purpose); j += 2) {
while (for_factor_purpose % j == 0) { // this while loop is for getting the digit sum of every prime
// factor that j has
int inner_digit = 0, inner_temp = j, inner_digit_sum = 0;
while (inner_temp > 0) {
inner_digit = inner_temp % 10;
second += inner_digit;
inner_temp /= 10;
}
// System.out.println("the second sum is " + second);
for_factor_purpose /= j;
}
}
int last_temp = for_factor_purpose, last_digit = 0, last_digit_sum = 0;
if (for_factor_purpose > 2) {
while (last_temp > 0) {
last_digit = last_temp % 10;
last += last_digit;
last_temp /= 10;
}
// System.out.println("last is " + last);
}
smith_sum = first + second + last;
// System.out.println("smith num is "+ smith_sum);
// System.out.println(smith_sum);
if (smith_sum == digit_sum) {
System.out.println("the num founded is" + i);
}
}
}
}
public static boolean isPrime(int i) {
int sqrt = (int) Math.sqrt(i) + 1;
for (int k = 2; k < sqrt; k++) {
if (i % k == 0) {
// number is perfectly divisible - no prime
return false;
}
}
return true;
}
the output is:
the num founded is4
the num founded is9
the num founded is22
the num founded is25
the num founded is27
the num founded is49
how ever the smith number between this range(1 and 50) are:
4, 22 and 27
edit:I_ve found the problem which is :
Math.sqrt(for_factor_purpose) it seems i should add 1 to it to eliminate square numbers. Thanks to you guys i've see sthe solution on other perspectives.
Keep coding!
Main loop for printing Smith numbers.
for (int i = 3; i < 10000; i++) {
if (isSmith(i)) {
System.out.println(i + " is a Smith number.");
}
}
The test method to determine if the supplied number is a Smith number. The list of primes is only increased if the last prime is smaller in magnitude than the number under test.
static boolean isSmith(int v) {
int sum = 0;
int save = v;
int lastPrime = primes.get(primes.size() - 1);
if (lastPrime < v) {
genPrimes(v);
}
outer:
for (int p : primes) {
while (save > 1) {
if (save % p != 0) {
continue outer;
}
sum += sumOfDigits(p);
save /= p;
}
break;
}
return sum == sumOfDigits(v) && !primes.contains(v);
}
Helper method to sum the digits of a number.
static int sumOfDigits(int i) {
return String.valueOf(i).chars().map(c -> c - '0').sum();
}
And the prime generator. It uses the list as it is created to determine if a given
number is a prime.
static List<Integer> primes = new ArrayList<>(List.of(2, 3));
static void genPrimes(int max) {
int next = primes.get(primes.size() - 1);
outer:
while (next <= max) {
next += 2;
for (int p : primes) {
if (next % p == 0) {
continue outer;
}
if (p * p > next) {
break;
}
}
primes.add(next);
}
}
}
I do not want to spoil the answer finding, but just some simpler code snippets,
making everything simpler, and more readable.
public boolean isSmith(int a) {
if (a < 2) return false;
int factor = findDivisor(a);
if (factor == a) return false;
int sum = digitSum(a);
// loop:
a /= factor;
sum -= digitSum(factor);
...
}
boolean isPrime(int a){
for(int i = 2; i*i <= a; i++) {
if (a % i == 0) {
return false;
}
}
return true;
}
int findDivisor(int a){
for(int i = 2; i*i <= a; i++) {
if (a % i == 0) {
return i;
}
}
return a;
}
int digitSum(int a) {
if (a < 10) {
return a;
}
int digit = a % 10;
int rest = a / 10;
return digit + digitSum(rest);
}
As you see integer division 23 / 10 == 2, and modulo (remainder) %: 23 % 10 == 3 can simplify things.
Instead of isPrime, finding factor(s) is more logical. In fact the best solution is not using findDivisor, but immediately find all factors
int factorsSum = 0;
int factorsCount = 0;
for(int i = 2; i*i <= a; i++) {
while (a % i == 0) {
factorsSum += digitSum(i);
a /= i;
factorsCount++;
}
}
// The remaining factor >= sqrt(original a) must be a prime.
// (It cannot contain smaller factors.)
factorsSum += digitSum(a);
factorsCount++;
Here is the code. If you need further help, please let me know. The code is pretty self explanatory and a decent bit was taken from your code but if you need me to explain it let me know.
In short, I created methods to check if a number is a smith number and then checked each int in the range.
import java.util.*;
public class MyClass {
public static void main(String args[]) {
System.out.println(smithInRange)
}
public int factor;
public boolean smithInRange(int a, int b){
for (int i=Math.min(a,b);i<=Math.max(a,b);i++) if(isSmith(i)) return true;
return false;
}
public boolean isSmith(int a){
if(a<2) return false;
if(isPrime(a)) return false;
int digits=0;
int factors=0;
String x=a+¨" ";
for(int i=0;i<x.length()-1;i++) digits+= Integer.parseInt(x.substring(i,i+1));
ArrayList<Integer> pF = new ArrayList<Integer>();
pF.add(a);
while(!aIsPrime(pF)){
int num = pF.get(pF.size-1)
pF.remove(pF.size()-1);
pF.add(factor);
pF.add(num/factor)
}
for(int i: pF){
if((factors+"").length()==1)factors+= i;
else{
String ss= i+" ";
int nums=0;
for(int j=0;j<ss.length()-1;j++){
nums+=Integer.parseInt(ss.substring(j,j+1));
}
}
}
return (factors==digits);
}
public boolean isPrime(int a){
for(int i=2;i<=(int)Math.sqrt(a),i++){
String s = (double)a/(double)i+"";
if(s.substring(s.length()-2).equals(".0")){
return false;
factor = i;
}
}
return true;
}
public boolean aIsPrime(ArrayList<int> a){
for(int i: a) if (!isPrime(a)) return false;
return true;
}
}

Prime numbers in a given range with less complexity

I have used below programs to find first n prime numbers (in below program it is from 2 to n). Can we write a program with single for loop? I also tried recursive approach but it is not working for me.
public static void main(String[] args) {
// Prime numbers in a range
int range = 15;
int num = 1;
int count = 0;
boolean prime = true;
while (count < range) {
num = num + 1;
prime = true;
for (int i = 2; i <= num / 2; i++) {
if (num % i == 0) {
prime = false;
break;
}
}
if (prime) {
count++;
System.out.println(num);
}
}
}
i dont think you can reduce it to one loop. But you can improve your code as Luca mentioned it.
public class PrimeFinder {
private final List<Integer> primes;
private final int primeCapacity;
public PrimeFinder(final int primeCapacity) {
if (primeCapacity < 3) {
throw new IllegalArgumentException("Tkat is way to easy.");
}
this.primeCapacity = primeCapacity;
primes = new ArrayList<>(primeCapacity);
primes.add(2);
}
public void find() {
final Index currentNumber = new Index();
while (primes.size() < primeCapacity) {
if (!primes.stream().parallel().anyMatch(prime -> (currentNumber.value % prime) == 0)) {
primes.add(currentNumber.incremet());
} else {
currentNumber.incremet();
}
}
}
public List<Integer> getPrimes() {
return primes;
}
private class Index {
public int value = 3;
public int incremet() {
return value++;
}
}
public static void main(String[] args) {
PrimeFinder primeFinder = new PrimeFinder(100000);
final long start = System.currentTimeMillis();
primeFinder.find();
final long finish = System.currentTimeMillis();
System.out.println("Score after " + (finish - start) + " milis.");
primeFinder.getPrimes().stream().forEach((prime) -> {
System.out.println(prime);
});
}
}
main rule here is simple, if given number isnt clearly divided by any prime number that you already have found, then it is prime number.
P.S. dont forget that primes.strem().... is loop also, so it is not a one loop code.
P.S.S. you can reduce this much further.
to understand the complexity of your algorithm you don't have to count the number of inner loops but the number of times you are iterating over your elements. To improve the performance of your algorithm you need to investigate if there are some iterations that could be unnecessary.
In your case when you do
for (int i = 2; i <= num / 2; i++) you are testing your num against values that are not necessary.. ex: if a number is divisible by 4 it will be by 2 too.
when you do for (int i = 2; i <= num / 2; i++) with num = 11
i will assume the values 2,3,4,5. 4 here is a not interesting number and represent an iteration that could be avoided.
anyway according to wikipedia the sieve of Eratosthenes is one of the most efficient ways to find all of the smaller primes.
public class PrimeSieve {
public static void main(String[] args) {
int N = Integer.parseInt(args[0]);
// 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;
}
}
}
// count primes
int primes = 0;
for (int i = 2; i <= N; i++) {
if (isPrime[i]) primes++;
}
System.out.println("The number of primes <= " + N + " is " + primes);
}
}
I don't know any way use a single loop for your question, but I do see two places where you can reduce the complexity:
Cache the prime numbers you found and use these prime numbers to decide if a number is prime or not. For example, to decide if 11 is a prime number, you just need to divide it by 2,3,5,7 instead of 2,3,4,5,6,...10
You don't need to check till num/2, you only need to check till the square root of num. For example, for 10, you only need to check 2,3 instead of 2,3,4,5. Because if number n is not prime, then n = a * b where either a or b is smaller than the square root x of n). If a is the smaller one, knowing that n can be divided by a is enough to decide that n is not prime.
So combining 1 & 2, you can improve the efficiency of your loops:
public static void main(String[] args) {
// Prime numbers in a range
int range = 15;
int num = 1;
int count = 0;
boolean prime = true;
ArrayList<Integer> primes = new ArrayList<>(range);
while (num < range) {
num = num + 1;
prime = true;
int numSquareRoot = (int) Math.floor(Math.pow(num, 0.5));
for (Integer smallPrimes : primes) {// only need to divide by the primes smaller than num
if (numSquareRoot > numSquareRoot) {// only need to check till the square root of num
break;
}
if (num % smallPrimes == 0) {
prime = false;
break;
}
}
if (prime) {
System.out.println(num);
primes.add(num);// cache the primes
}
}
}

Write function which is return array of prime factors

I have a function it returns prime factors of a number but when I initialize int array I set size.So the result consists unnecessary zeros.How can I return result array without zeros or how can I initialize array applicable size? I am not using Lists
public static int[] encodeNumber(int n){
int i;
int j = 0;
int[] prime_factors = new int[j];
if(n <= 1) return null;
for(i = 2; i <= n; i++){
if(n % i == 0){
n /= i;
prime_factors[j] = i;
i--;
j++;
}
}
return prime_factors;
}
Thanx!!!
Here is a quick way to get about the prime factors problem that I recently worked out. I don't claim it is original, but I did create it on my own. Actually had to do this in C, where I wanted to malloc only once.
public static int[] getPrimeFactors(final int i) {
return getPrimeFactors1(i, 0, 2);
}
private static int[] getPrimeFactors1(int number, final int numberOfFactorsFound, final int startAt) {
if (number <= 1) { return new int[numberOfFactorsFound]; }
if (isPrime(number)) {
final int[] toReturn = new int[numberOfFactorsFound + 1];
toReturn[numberOfFactorsFound] = number;
return toReturn;
}
final int[] toReturn;
int currentFactor = startAt;
final int currentIndex = numberOfFactorsFound;
int numberOfRepeatations = 0;
// we can loop unbounded by the currentFactor, because
// All non prime numbers can be represented as product of primes!
while (!(isPrime(currentFactor) && number % currentFactor == 0)) {
currentFactor += currentFactor == 2 ? 1 : 2;
}
while (number % currentFactor == 0) {
number /= currentFactor;
numberOfRepeatations++;
}
toReturn = getPrimeFactors1(number, currentIndex + numberOfRepeatations, currentFactor + (currentFactor == 2 ? 1 : 2));
while (numberOfRepeatations > 0) {
toReturn[currentIndex + --numberOfRepeatations] = currentFactor;
}
return toReturn;
}
Allocate as many factors as you think the number may have (32 sounds like a good candidate), and then use Arrays.copyOf() to cut off the array at the actual limit:
return Arrays.copyOf(prime_factors, j);

Calculate nth prime.. in java?

I am printing out a list of prime numbers in a program and storing it an array. Then I want to get the the prime number on a particular index instead of the total list..
import java.util.*;
public class Gauss {
static int n;
static int[] array;
public static void Input() {
Scanner input = new Scanner(System.in);
System.out.println("Enter N: ");
n = input.nextInt();
}
public static boolean isPrime(int num) {
boolean prime = true;
int limit = (int) Math.sqrt(num);
for (int i = 2; i <= limit; i++) {
if (num % i == 0) {
prime = false;
break;
}
}
return prime;
}
public static void Calc() {
Input();
array = new int[1000];
for (int i = 2; i < array.length; i++) {
array[i] = i;
}
ArrayList<Integer> list = new ArrayList<Integer>(array.length);
for (int c : array) {
list.add(c);
}
list.remove(0);
list.remove(0);
Collections.sort(list);
for (int k : list) {
if (isPrime(k)) {
System.out.println(k);
}
}
}
public static void main(String[] args) {
Calc();
}
}
To get the nth prime just use array[n-1]
You might find this answer useful to a similar question.
And you can get the nth prime numbers with
List<Integer> primes = findPrimes(0, n);
System.out.println( primes.get(i) );
** EDIT **
Here is the integral test program that I came up (modified since the last posted answer above) with benchmark tests and all. I know there are faster implementations, and some optimizations can still be made, but here are some algorithms to generate prime numbers :
public class PrimeTests {
public static void main(String... args) {
AbstractPrimeGenerator[] generators = new AbstractPrimeGenerator[] {
new DefaultPrimeGenerator(),
new AtkinSievePrimeGenerator(),
new SundaramSievePrimeGenerator()
};
int[] primes;
int[] old_primes = null;
double[] testAvg = new double[generators.length];
long ts, te;
double time;
DecimalFormat df = new DecimalFormat("0.0######################");
int max = 10000000;
int testCountLoop = 10;
int it = 0, ti;
while (it++ < testCountLoop) {
ti = 0;
for (AbstractPrimeGenerator g : generators) {
ti++;
System.out.println(it + "." + ti + ". Calculating " + max
+ " primes numbers from " + g.getName() + "...");
ts = System.nanoTime();
primes = g.findPrimes(max);
te = System.nanoTime();
time = (te - ts) * Math.pow(10, -9) * 1000;
df.setRoundingMode(RoundingMode.HALF_UP);
testAvg[ti - 1] += time;
System.out.println("Found " + primes.length
+ " prime numbers (in " + time + " ms, "
+ df.format(time / primes.length) + " ms per prime)");
// for (int prime : primes) {
// System.out.print(prime + "... ");
// }
// System.out.println();
if (old_primes != null) {
System.out.print("Validating primes.... ");
if (primes.length == old_primes.length) {
for (int i = 0; i < primes.length; i++) {
if (primes[i] != old_primes[i]) {
System.out.println("Prime number does not match : " + primes[i] + " != " + old_primes[i] + " at index " + i);
System.exit(-1);
}
}
} else {
System.out.println("ERROR!! No match in prime results");
System.exit(-1);
}
System.out.println("Ok!");
}
old_primes = primes;
}
System.out.println("................");
}
System.out.println("Results:");
ti = 0;
for (AbstractPrimeGenerator g : generators) {
time = (testAvg[ti++] / testCountLoop);
System.out.println(ti + ". Average time finding " + max
+ " primes numbers from " + g.getName() + " = " + time
+ " ms or " + df.format(time / old_primes.length)
+ " ms per prime");
}
System.out.println("Done!");
}
/**
* Base class for a prime number generator
*/
static abstract public class AbstractPrimeGenerator {
/**
* The name of the generator
*
* #return String
*/
abstract public String getName();
/**
* Returns all the prime numbers where (2 <= p <= max)
*
* #param max
* int the maximum value to test for a prime
* #return int[] an array of prime numbers
*/
abstract public int[] findPrimes(int max);
}
/**
* Default naive prime number generator. Based on the assumption that any
* prime n is not divisible by any other prime m < n (or more precisely m <=
* sqrt(n))
*/
static public class DefaultPrimeGenerator extends AbstractPrimeGenerator {
#Override
public String getName() {
return "Default generator";
}
#Override
public int[] findPrimes(int max) {
int[] primes = new int[max];
int found = 0;
boolean isPrime;
// initial prime
if (max > 2) {
primes[found++] = 2;
for (int x = 3; x <= max; x += 2) {
isPrime = true; // prove it's not prime
for (int i = 0; i < found; i++) {
isPrime = x % primes[i] != 0; // x is not prime if it is
// divisible by p[i]
if (!isPrime || primes[i] * primes[i] > x) {
break;
}
}
if (isPrime) {
primes[found++] = x; // add x to our prime numbers
}
}
}
return Arrays.copyOf(primes, found);
}
}
/**
* Sieve of Atkin prime number generator Implementation following the Sieve
* of Atkin to generate prime numbers
*
* #see http://en.wikipedia.org/wiki/Sieve_of_Atkin
*/
static public class AtkinSievePrimeGenerator extends AbstractPrimeGenerator {
#Override
public String getName() {
return "Sieve of Atkin generator";
}
#Override
public int[] findPrimes(int max) {
boolean[] isPrime = new boolean[max + 1];
double sqrt = Math.sqrt(max);
for (int x = 1; x <= sqrt; x++) {
for (int y = 1; y <= sqrt; y++) {
int n = 4 * x * x + y * y;
if (n <= max && (n % 12 == 1 || n % 12 == 5)) {
isPrime[n] = !isPrime[n];
}
n = 3 * x * x + y * y;
if (n <= max && (n % 12 == 7)) {
isPrime[n] = !isPrime[n];
}
n = 3 * x * x - y * y;
if (x > y && (n <= max) && (n % 12 == 11)) {
isPrime[n] = !isPrime[n];
}
}
}
for (int n = 5; n <= sqrt; n++) {
if (isPrime[n]) {
int s = n * n;
for (int k = s; k <= max; k += s) {
isPrime[k] = false;
}
}
}
int[] primes = new int[max];
int found = 0;
if (max > 2) {
primes[found++] = 2;
}
if (max > 3) {
primes[found++] = 3;
}
for (int n = 5; n <= max; n += 2) {
if (isPrime[n]) {
primes[found++] = n;
}
}
return Arrays.copyOf(primes, found);
}
}
/**
* Sieve of Sundaram prime number generator Implementation following the
* Sieve of Sundaram to generate prime numbers
*
* #see http://en.wikipedia.org/wiki/Sieve_of_Sundaram
*/
static public class SundaramSievePrimeGenerator extends
AbstractPrimeGenerator {
#Override
public String getName() {
return "Sieve of Sundaram generator";
}
#Override
public int[] findPrimes(int max) {
int n = max / 2;
boolean[] isPrime = new boolean[max];
Arrays.fill(isPrime, true);
for (int i = 1; i < n; i++) {
for (int j = i; j <= (n - i) / (2 * i + 1); j++) {
isPrime[i + j + 2 * i * j] = false;
}
}
int[] primes = new int[max];
int found = 0;
if (max > 2) {
primes[found++] = 2;
}
for (int i = 1; i < n; i++) {
if (isPrime[i]) {
primes[found++] = i * 2 + 1;
}
}
return Arrays.copyOf(primes, found);
}
}
}
On my machine, the result gives :
Results:
1. Average time finding 10000000 primes numbers from Default generator = 1108.7848961000002 ms or 0.0016684019448402676 ms per prime
2. Average time finding 10000000 primes numbers from Sieve of Atkin generator = 199.8792727 ms or 0.0003007607413114167 ms per prime
3. Average time finding 10000000 primes numbers from Sieve of Sundaram generator = 132.6467922 ms or 0.00019959522073372766 ms per prime
Using one of the class's method above (you don't need the actual base class and all, only the actual method), you can do :
public class PrimeTest2 {
static public int[] findPrimes(int max) {
int[] primes = new int[max];
int found = 0;
boolean isPrime;
// initial prime
if (max > 2) {
primes[found++] = 2;
for (int x = 3; x <= max; x += 2) {
isPrime = true; // prove it's not prime
for (int i = 0; i < found; i++) {
isPrime = x % primes[i] != 0; // x is not prime if it is
// divisible by p[i]
if (!isPrime || primes[i] * primes[i] > x) {
break;
}
}
if (isPrime) {
primes[found++] = x; // add x to our prime numbers
}
}
}
return Arrays.copyOf(primes, found);
}
public static void main(String... args) {
Scanner input = new Scanner(System.in);
int MAX_N = Integer.MAX_VALUE / 100;
int n = 0;
while (n <= 0 || n >= MAX_N) {
System.out.print("Enter N: ");
n = input.nextInt();
if (n <= 0) {
System.out.println("n must be greater than 0");
}
if (n >= MAX_N) {
System.out.println("n must be smaller than " + MAX_N);
}
}
int max = n * 100; // just find enough prime numbers....
int[] primes = findPrimes(max);
System.out.println("Number of prime numbers found from " + 0 + " to "
+ max + " = " + primes.length);
System.out.println("The " + n
+ (n == 1 ? "st" : n == 2 ? "nd" : n == 3 ? "rd" : "th")
+ " prime number is : " + primes[n - 1]);
}
}
Which will output (for example) :
Enter N: 10000
Number of prime numbers found from 0 to 1000000 = 78498
The 10000th prime number is : 104729
With that in hand, you pretty have all that is to say about finding the nth prime number. For larger numbers (beyond int's), you'll have to modify the "default generator's" un-optimized method to accept long or use other methodologies (i.e. other language and/or libraries)
Cheers!
The code you have is pretty much the way to go, and Roflcopter's answer for picking the number is correct, but there is one optimization you could do that would significantly increase the performance. Instead of dividing by all numbers less than or equal to the square root, divide only by PRIMES less than or equal to the square root. Any number not divisible by any prime you've found so far is also not divisible by any combination of same, which is the definition of a nonprime number (having a prime factorization other than 1*N)

Categories