Finding largest prime number out of 600851475143? - java

I'm trying to solve problem 3 from http://projecteuler.net. However, when I run thing program nothing prints out.
What am I doing wrong?
Problem: What is the largest prime factor of the number 600851475143 ?
public class project_3
{
public boolean prime(long x) // if x is prime return true
{
boolean bool = false;
for(long count=1L; count<x; count++)
{
if( x%count==0 )
{
bool = false;
break;
}
else { bool = true; }
}
return bool;
}
public static void main(String[] args)
{
long ultprime = 0L; // largest prime value
project_3 object = new project_3();
for(long x=1L; x <= 600851475143L; x++)
{
if( object.prime(x)==true )
{
ultprime = ((x>ultprime) ? x : ultprime);
}
}
System.out.println(ultprime);
}
}

Not only does your prime checking function always return false; even if it were functioning properly, your main loop does not seek the input number's factors at all, but rather just the largest prime smaller or equal to it. In pseudocode, your code is equivalent to:
foo(n):
x := 0 ;
foreach d from 1 to n step 1:
if is_prime(d): // always false
x := d
return x // always 0
is_prime(d):
not( d % 1 == 0 ) // always false
But you don't need the prime checking function here at all. The following finds all factors of a number, by trial division:
factors(n):
fs := []
d := 2
while ( d <= n/d ):
if ( n % d == 0 ): { n := n/d ; fs := append(fs,d) }
else: { d := d+1 }
if ( n > 1 ): { fs := append(fs, n) }
return fs
The testing for divisibility is done only up to the square root of the number. Each factor, as it is found, is divided out of the number being factorized, thus further reducing the run time. Factorization of the number in question runs instantly, taking just 1473 iterations.
By construction all the factors thus found are guaranteed to be prime (that's why no prime checking is needed). It is crucial to enumerate the possible divisors in ascending order for this to happen1. Ascending order is also the most efficient, because any given number is more likely to have smaller prime factor than larger one. Enumerating the primes instead of odds, though not necessary, will be more efficient if you have an efficient way of getting those primes, to test divide by.
It is trivial to augment the above to find the largest factor: just implement append as
append(fs,d):
return d
1
because then for any composite divisor d of the original number being factorized, when we'll reach d, we will have already divided its prime factors out of the original number, and so the reduced number will have no common prime factors with it, i.e. d won't divide the reduced number even though it divides the original.

Two things:
1) You are starting count at 1 instead of 2. All integers are divisible by 1.
2) You are running an O(n^2) algorithm against a rather large N (or at least you will be once you fix point #1). The runtime will be quite long.

The whole point of Project Euler is that the most obvious approaches to finding the answer will take so long to compute that they aren't worth running. That way you learn to look for the less obvious, more efficient approaches.
Your approach is technically correct in terms of whether or not it is capable of computing the largest prime of some number. The reason you aren't seeing anything print out is that your algorithm is not capable of solving the problem quickly.
The way you've designed this, it'll take somewhere around 4,000,000 years to finish.
If you replaced the 600851475143 number with say 20 it would be able to finish fairly quickly. But you have the 600 billion number, so it's not that simple.

Related

Create a class PrimeRandomGenerator that extends class RandomGenerator

I have to create a class that extends RandomGenerator and produces a random prime number each time the user enters an interval in the main program.
I have created the constructors and the isPrime method but I can't figure out what to do next.
That's how far I got. I am sure there are mistakes in this, but I just can't see them.
public class RandomGeneratorImproved extends RandomGenerator {
public RandomGeneratorImproved(int prime) {
int startp=0;
int tillp=prime-1;
}
public RandomGeneratorImproved(int lowp,int upperp) {
int startp=lowp;
int tillp=upperp;
}
public boolean isPrime(int startp,int tillp) {
int prime=rgen.nextInt(startp,tillp);
int n=0;
if (prime<=1) {
return false;
} else if (prime<=3) {
return true;
} else if (prime%2==0 || prime%3==0){
return false;
}
for (int i=5;i<(prime/i);i+=6) {
if (prime%i==0) {
return false;
}
}
return true;
}
private RandomGenerator rgen= RandomGenerator.getInstance();
}
Notes:
If the user enters only one number ( lets say: x ) then the interval will be (0,x).In other words we have to create either two methods either two constructors.
For example:
public int nextPrime(int n) or public int nextPrime(int low,int high)
I am not allowed to use arrays (or other ready-made methods that make the problem way easier).
I searched everything that involved Random Prime Numbers Generators but I couldn't find anything similar to this.
Some advice on how to improve and use the class.
I have to create a class that extends RandomGenerator and produces a random prime number each time the user enters an interval in the main program.
That tells me that the instance of your class is not associated with a range at its creation. The range is given only on the user's demand to generate a prime. As such, I would
Create an empty constructor and to whatever initialization there is to do there.
Add overloaded methods public int generatePrime(int high) and public int generatePrime(int low, int high). Generally, overloaded methods with less arguments (less data) should just call the most specific method by completing the needed data (see code below).
The method name isPrime suggests that it should check if a single given int is a prime or not. I would make it boolean isPrime(int primeQ).
The only step left is to figure out what ints to give to isPrime from the specified range. Since the superclass has a method that generates a random int in the range, you can pass it to isPrime to check if it is a prime. If it is, return it, otherwise try again. Note that this is extremely inefficient, but with the lack of tools and info this is the simplest bridge I could find.
Here is the code:
public class RandomGeneratorImproved extends RandomGenerator {
private RandomGenerator rgen;
public RandomGeneratorImproved() {
rgen = RandomGenerator.getInstance();
}
public int generatePrime(int prime) {
return generatePrime(0, prime - 1);
}
public int generatePrime(int lowp, int upperp) {
int prime = rgen.nextInt(lowp, upperp);
while (!isPrime(prime))
prime = rgen.nextInt(lowp, upperp);
return prime;
}
public boolean isPrime(int prime) {
int n = 0; // <------ this is not used
if (prime <= 1) {
return false;
}
else if (prime <= 3) {
return true;
}
else if (prime % 2 == 0 || prime % 3 == 0) {
return false;
}
for (int i = 5; i < (prime / i); i += 6) {
if (prime % i == 0) {
return false;// "random number"+prime+"is not a prime number";
}
}
return true;// "random number"+prime+"is a prime number";
}
}
Note that the line int n = 0; gives a warning that n is never used. You might want to remove it.
The usage would be:
RandomGeneratorImproved rpg = new RandomGeneratorImproved();
int generatedPrime = rpg.generatePrime(6, 30);
int generatedPrime2 = rpg.generatePrime(30); // same as rpg.generatePrime(1, 30)
The rejection method - generating a random number in the range of interest, checking whether it satisfies the target criteria and returning it if it does else repeating the process - has the advantage that it produces perfectly unbiased results. Its disadvantage is performance (or lack thereof).
Also, trial division is just about the slowest primality test method known to Man. Depending on the use of the 'random primes', different approaches are possible. They all require the prime factors up to the square root of the upper end of the range to be available in some form, but so does Trial Division.
Alternative 1: The Peepholes of Eratosthenes
Given that the target range seems to be limited to small integers, the following approach is feasible: draw a random number k, sieve the range [max(2, k - 335), k] using a windowed Sieve of Eratosthenes and return the highest prime in that range. This works because the gaps between primes up to 4,302,407,359 are no wider than 336. Hence the tiny window ('peephole') must necessarily contain a prime.
Disadvantage: the resulting distribution of primes is uneven (biased). For example, the number 2 will only be returned if k == 2 since the next higher prime (3) is right next to it. By contrast, the number 3,842,610,773 is followed by 335 non-primes and so the probability of its being drawn is 336 times as high as that for the number 2. However, proving the bias by looking at the output isn't easy, and for automated testers it should be near impossible.
Caveat: in this context the sieving always needs to process all prime factors up to the square root of k, which involves one modulo division per prime for computing the start offset within the window. By contrast, Trial Division can reject more than 85% of all composites based on just the first dozen primes alone. Hence there's probably no situation where Peepholes actually has an advantage over Trial Division.
Alternative 2: The Lazy Segmented Eratosthenes
Sieving the first 2^31 numbers takes quite a bit of CPU time (about 1 CPU second in C++, lots more in Java), and a lot of that effort goes to waste unless random primes are needed in great bulk, to the tune of many millions. If only a tiny handful of random primes is needed then Trial Division is indeed the way to go but if more are desired then a lazy approach to segmented sieving can help.
Pick a segment size that does not exceed the size of the L1 cache and create a segment cache array that covers the whole target range. After drawing a random k, retrieve the reference for the corresponding segment from the cache; if it is nil, sieve the segment and store the reference in the appropriate cache slot. Then you have a segment reference in any case, so you can test the primality of k by checking the bit (k >> 1) % segment_size in the segment, assuming an odds-only sieve.
Segments should be packed bitmaps representing odd numbers, and % segment_size can be computed by masking if the segment size is a power of 2. This way you always get an answer quickly without the long wait for sieving the whole range in one go. And the efficiency goes up when you need it to (i.e. when you are drawing lots of random primes) because the cache fills itself, causing more and more primality queries to be satisfied by already-existing segments.
Unlike the Peephole method, this gives a perfectly unbiased distribution (which is kind of obvious, since it only replaces the primality test but not the actual method of drawing primes).
There's some more info in a post on Code Review that discusses the challenge of drawing 100 random primes.

Pollard Rho can't find factor

So I am attempting to create a Pollard's Rho Factoring Algorithm in Java using the BigInteger class to support very large integers. The code mostly works but cannot find a factor for 4 or 8 (which should be 2). Currently I have capped it to cycle through the algorithm 10,000,000 times and still it can't find 2 as a factor. a is generated randomly (limited between 0 and 1000). Is this just a flaw in the Pollard Rho Algorithm or is there a mistake somewhere in the implementation?
The n being passed is 4
The initial a is calculated as a random the same way in the below code, between 0 and 1000
The sqrt(n) method returns the floor of the square root of n (in this case sqrt(sqrt(4)) = 1
I printed count at the end to make sure it was actually iterating how many times it was supposed to.
private static BigInteger PollardRho (BigInteger a, BigInteger n) {
BigInteger gcd = BigInteger.ZERO;
BigInteger Tort = a;
BigInteger Hare = a;
BigInteger count = BigInteger.ZERO;
BigInteger iterationLim = (sqrt(sqrt(n))).multiply(BigInteger.valueOf(10000000));
while (count.compareTo(iterationLim)!=0)
//makes sure that the algorithm does not surpass (4th root of n)*10000000 iterations.
{
Tort = ((Tort.pow(2)).add(BigInteger.ONE)).mod(n);
//System.out.println("Tort: "+Tort);
Hare = (((Hare.pow(2)).add(BigInteger.ONE).pow(2)).add(BigInteger.ONE)).mod(n);
//System.out.println("Hare: "+Hare);
gcd = (Tort.subtract(Hare)).gcd(n);
//System.out.println("gcd: "+gcd);
if (gcd.compareTo(BigInteger.ONE) != 0 && gcd.compareTo(n) != 0)
{
// System.out.println("took if, gcd = "+gcd);
return gcd;
}
if (gcd.compareTo(n) == 0)
{
a = (BigInteger.valueOf((long) (1000*Math.random())));
Tort = a;
Hare = a;
}
count = count.add(BigInteger.ONE);
}
System.out.println(count);
return n;
}
Pollard's Rho method usually can only split numbers composed of different primes. It fails most of the time for numbers that are prime powers. 4 and 8 are powers of a single prime 2 and therefore unlikely to be split by this method.
The method works by iterating a random function f(x) mod n, in this case f(x) = x^2+1 is used, but other functions work as well. The trick is that f(x) mod p where p is a prime factor of n enters a cycle after a different number of iterations for different primes. So f(x) mod p1 may already be in a cycle, f(x) mod p2 not yet. The gcd calculation is then able to find the factor p1.
It is btw. very easy to check if a number is a proper power of an integer. Just calculate the 2nd, 3rd, 4th, ... root and check if it is an integer.

Issue with implementation of Fermat's little therorm

Here's my implementation of Fermat's little theorem. Does anyone know why it's not working?
Here are the rules I'm following:
Let n be the number to test for primality.
Pick any integer a between 2 and n-1.
compute a^n mod n.
check whether a^n = a mod n.
myCode:
int low = 2;
int high = n -1;
Random rand = new Random();
//Pick any integer a between 2 and n-1.
Double a = (double) (rand.nextInt(high-low) + low);
//compute:a^n = a mod n
Double val = Math.pow(a,n) % n;
//check whether a^n = a mod n
if(a.equals(val)){
return "True";
}else{
return "False";
}
This is a list of primes less than 100000. Whenever I input in any of these numbers, instead of getting 'true', I get 'false'.
The First 100,008 Primes
This is the reason why I believe the code isn't working.
In java, a double only has a limited precision of about 15 to 17 digits. This means that while you can compute the value of Math.pow(a,n), for very large numbers, you have no guarantee you'll get an exact result once the value has more than 15 digits.
With large values of a or n, your computation will exceed that limit. For example
Math.pow(3, 67) will have a value of 9.270946314789783e31 which means that any digit after the last 3 is lost. For this reason, after applying the modulo operation, you have no guarantee to get the right result (example).
This means that your code does not actually test what you think it does. This is inherent to the way floating point numbers work and you must change the way you hold your values to solve this problem. You could use long but then you would have problems with overflows (a long cannot hold a value greater than 2^64 - 1 so again, in the case of 3^67 you'd have another problem.
One solution is to use a class designed to hold arbitrary large numbers such as BigInteger which is part of the Java SE API.
As the others have noted, taking the power will quickly overflow. For example, if you are picking a number n to test for primality as small as say, 30, and the random number a is 20, 20^30 = about 10^39 which is something >> 2^90. (I took the ln of 10^39).
You want to use BigInteger, which even has the exact method you want:
public BigInteger modPow(BigInteger exponent, BigInteger m)
"Returns a BigInteger whose value is (this^exponent mod m)"
Also, I don't think that testing a single random number between 2 and n-1 will "prove" anything. You have to loop through all the integers between 2 and n-1.
#evthim Even if you have used the modPow function of the BigInteger class, you cannot get all the prime numbers in the range you selected correctly. To clarify the issue further, you will get all the prime numbers in the range, but some numbers you have are not prime. If you rearrange this code using the BigInteger class. When you try all 64-bit numbers, some non-prime numbers will also write. These numbers are as follows;
341, 561, 645, 1105, 1387, 1729, 1905, 2047, 2465, 2701, 2821, 3277, 4033, 4369, 4371, 4681, 5461, 6601, 7957, 8321, 8481, 8911, 10261, 10585, 11305, 12801, 13741, 13747, 13981, 14491, 15709, 15841, 16705, 18705, 18721, 19951, 23001, 23377, 25761, 29341, ...
https://oeis.org/a001567
161038, 215326, 2568226, 3020626, 7866046, 9115426, 49699666, 143742226, 161292286, 196116194, 209665666, 213388066, 293974066, 336408382, 376366, 666, 566, 566, 666 2001038066, 2138882626, 2952654706, 3220041826, ...
https://oeis.org/a006935
As a solution, make sure that the number you tested is not in this list by getting a list of these numbers from the link below.
http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
The solution for C # is as follows.
public static bool IsPrime(ulong number)
{
return number == 2
? true
: (BigInterger.ModPow(2, number, number) == 2
? (number & 1 != 0 && BinarySearchInA001567(number) == false)
: false)
}
public static bool BinarySearchInA001567(ulong number)
{
// Is number in list?
// todo: Binary Search in A001567 (https://oeis.org/A001567) below 2 ^ 64
// Only 2.35 Gigabytes as a text file http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
}

Dealing with overflow in Java without using BigInteger

Suppose I have a method to calculate combinations of r items from n items:
public static long combi(int n, int r) {
if ( r == n) return 1;
long numr = 1;
for(int i=n; i > (n-r); i--) {
numr *=i;
}
return numr/fact(r);
}
public static long fact(int n) {
long rs = 1;
if(n <2) return 1;
for (int i=2; i<=n; i++) {
rs *=i;
}
return rs;
}
As you can see it involves factorial which can easily overflow the result. For example if I have fact(200) for the foctorial method I get zero. The question is why do I get zero?
Secondly how do I deal with overflow in above context? The method should return largest possible number to fit in long if the result is too big instead of returning wrong answer.
One approach (but this could be wrong) is that if the result exceed some large number for example 1,400,000,000 then return remainder of result modulo
1,400,000,001. Can you explain what this means and how can I do that in Java?
Note that I do not guarantee that above methods are accurate for calculating factorial and combinations. Extra bonus if you can find errors and correct them.
Note that I can only use int or long and if it is unavoidable, can also use double. Other data types are not allowed.
I am not sure who marked this question as homework. This is NOT homework. I wish it was homework and i was back to future, young student at university. But I am old with more than 10 years working as programmer. I just want to practice developing highly optimized solutions in Java. In our times at university, Internet did not even exist. Today's students are lucky that they can even post their homework on site like SO.
Use the multiplicative formula, instead of the factorial formula.
Since its homework, I won't want to just give you a solution. However a hint I will give is that instead of calculating two large numbers and dividing the result, try calculating both together. e.g. calculate the numerator until its about to over flow, then calculate the denominator. In this last step you can chose the divide the numerator instead of multiplying the denominator. This stops both values from getting really large when the ratio of the two is relatively small.
I got this result before an overflow was detected.
combi(61,30) = 232714176627630544 which is 2.52% of Long.MAX_VALUE
The only "bug" I found in your code is not having any overflow detection, since you know its likely to be a problem. ;)
To answer your first question (why did you get zero), the values of fact() as computed by modular arithmetic were such that you hit a result with all 64 bits zero! Change your fact code to this:
public static long fact(int n) {
long rs = 1;
if( n <2) return 1;
for (int i=2; i<=n; i++) {
rs *=i;
System.out.println(rs);
}
return rs;
}
Take a look at the outputs! They are very interesting.
Now onto the second question....
It looks like you want to give exact integer (er, long) answers for values of n and r that fit, and throw an exception if they do not. This is a fair exercise.
To do this properly you should not use factorial at all. The trick is to recognize that C(n,r) can be computed incrementally by adding terms. This can be done using recursion with memoization, or by the multiplicative formula mentioned by Stefan Kendall.
As you accumulate the results into a long variable that you will use for your answer, check the value after each addition to see if it goes negative. When it does, throw an exception. If it stays positive, you can safely return your accumulated result as your answer.
To see why this works consider Pascal's triangle
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
which is generated like so:
C(0,0) = 1 (base case)
C(1,0) = 1 (base case)
C(1,1) = 1 (base case)
C(2,0) = 1 (base case)
C(2,1) = C(1,0) + C(1,1) = 2
C(2,2) = 1 (base case)
C(3,0) = 1 (base case)
C(3,1) = C(2,0) + C(2,1) = 3
C(3,2) = C(2,1) + C(2,2) = 3
...
When computing the value of C(n,r) using memoization, store the results of recursive invocations as you encounter them in a suitable structure such as an array or hashmap. Each value is the sum of two smaller numbers. The numbers start small and are always positive. Whenever you compute a new value (let's call it a subterm) you are adding smaller positive numbers. Recall from your computer organization class that whenever you add two modular positive numbers, there is an overflow if and only if the sum is negative. It only takes one overflow in the whole process for you to know that the C(n,r) you are looking for is too large.
This line of argument could be turned into a nice inductive proof, but that might be for another assignment, and perhaps another StackExchange site.
ADDENDUM
Here is a complete application you can run. (I haven't figured out how to get Java to run on codepad and ideone).
/**
* A demo showing how to do combinations using recursion and memoization, while detecting
* results that cannot fit in 64 bits.
*/
public class CombinationExample {
/**
* Returns the number of combinatios of r things out of n total.
*/
public static long combi(int n, int r) {
long[][] cache = new long[n + 1][n + 1];
if (n < 0 || r > n) {
throw new IllegalArgumentException("Nonsense args");
}
return c(n, r, cache);
}
/**
* Recursive helper for combi.
*/
private static long c(int n, int r, long[][] cache) {
if (r == 0 || r == n) {
return cache[n][r] = 1;
} else if (cache[n][r] != 0) {
return cache[n][r];
} else {
cache[n][r] = c(n-1, r-1, cache) + c(n-1, r, cache);
if (cache[n][r] < 0) {
throw new RuntimeException("Woops too big");
}
return cache[n][r];
}
}
/**
* Prints out a few example invocations.
*/
public static void main(String[] args) {
String[] data = ("0,0,3,1,4,4,5,2,10,0,10,10,10,4,9,7,70,8,295,100," +
"34,88,-2,7,9,-1,90,0,90,1,90,2,90,3,90,8,90,24").split(",");
for (int i = 0; i < data.length; i += 2) {
int n = Integer.valueOf(data[i]);
int r = Integer.valueOf(data[i + 1]);
System.out.printf("C(%d,%d) = ", n, r);
try {
System.out.println(combi(n, r));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
Hope it is useful. It's just a quick hack so you might want to clean it up a little.... Also note that a good solution would use proper unit testing, although this code does give nice output.
You can use the java.math.BigInteger class to deal with arbitrarily large numbers.
If you make the return type double, it can handle up to fact(170), but you'll lose some precision because of the nature of double (I don't know why you'd need exact precision for such huge numbers).
For input over 170, the result is infinity
Note that java.lang.Long includes constants for the min and max values for a long.
When you add together two signed 2s-complement positive values of a given size, and the result overflows, the result will be negative. Bit-wise, it will be the same bits you would have gotten with a larger representation, only the high-order bit will be truncated away.
Multiplying is a bit more complicated, unfortunately, since you can overflow by more than one bit.
But you can multiply in parts. Basically you break the to multipliers into low and high halves (or more than that, if you already have an "overflowed" value), perform the four possible multiplications between the four halves, then recombine the results. (It's really just like doing decimal multiplication by hand, but each "digit" is, say, 32 bits.)
You can copy the code from java.math.BigInteger to deal with arbitrarily large numbers. Go ahead and plagiarize.

Can someone please explain how this implementation works? Also, can it be made better? How?

public class Main {
public static void main(String args []){
long numberOfPrimes = 0; //Initialises variable numberOfPrimes to 0 (same for all other variables)
int number = 1;
int maxLimit = 10000000;
boolean[] sieve = new boolean[maxLimit]; //creates new boolean array called sieve and allocates space on the
//stack for this array which has maxLimit spaces in it
for ( int i = 2; i < maxLimit; i++ ) { //for statement cycling from 2 to 10000000, does not execute the rest
//of the block if the boolean value in the array is true
if ( sieve[i] == true ) continue;
numberOfPrimes++; //otherwise it increments the number of prime numbers found
if ( numberOfPrimes == 10001 ) { //if 10001st prime number is found, break from loop
number = i;
break;
}
for ( int j = i+i; j < maxLimit; j += i ) //do not understand the point of this loop logically
sieve[j] = true; //testing if the value in the array is true again?
}
System.out.println("10001st prime: "+ number);
}
}
I don't really understand what is going on in this program and was hoping somebody could explain it to me? I have commented the specific lines causing me trouble/what I understand lines to be doing. Thank you very much for all the help! :)
Make yourself familiar with Eratosthenes' Sieve algorithm. Wikipedia even has animated gif demonstrating the process. And your code is just a straightforward implementation of it.
Yes, this is your basic implementation of Eratosthenes' Sieve. There are quite a few ways in which you can improve it, but let's go over the basic principle first.
What you are doing is creating an array of boolean values. The INDEX in the array represents the number which we are testing to see if it is a prime or not.
Now you are going to start checking each number to see if it is a prime. First off, the definition of a prime is "all numbers divisible ONLY by itself and 1 without fractioning".
for ( int i = 2; i < maxLimit; i++ )
You start with the INDEX 2 (the number 3) because depending on your definition, 1 and 2 are always prime. (Some definitions say 1 is not a prime).
if ( sieve[i] == true ) continue;
If a number has been marked as a non-prime previously, we don't bother with the current iteration.
numberOfPrimes++;
if ( numberOfPrimes == 10001 ) {
number = i;
break;
}
If the INDEX we are at currently has not been marked as being a prime, it has to be one, so we increment the number of primes we have found. The next piece of code I'm assuming is part of the requirements of the program which states that if 10001 primes have been found, the program must exit. That part can be left out if you actually want to check for primes up to the maximum number defined in stead of for a specific number of primes.
for ( int j = i+i; j < maxLimit; j += i )
sieve[j] = true;
This is where the actual magic of the sieve starts. From the definition of a prime, a number cannot be a prime if it is divisible by anything other than itself and 1. Therefore, for any new number we find that is a prime, we can mark all it's factors as NOT being prime. For example, the first iteration of the for loop, we start with 3. Because sieve[2] is false (have not visited before), it is a prime (AND 3 IS A PRIME!). Then, all other factors of 3 CANNOT be primes. The above mentioned for loop goes through the entire sieve and marks all factors of 3 as false. So that loop will do: sieve[5] = true; sieve[8] = true ... up until the end of the sieve.
Now, when you reach the first number greater than the maximum defined initially, you can be certain that any number that has a factor has been marked as not being a prime. What you end up with is a boolean array, where each index marked as false, represents a prime number.
You can probably get a much better description on wikipedia, but this is the jist of it. Hope it helps!
for ( int j = i+i; j < maxLimit; j += i ) //dont understand the point of this loop logically
sieve[j] = true; //testing if the value in the array is true again ?
This is not a testing, but rather a setting. This loop is setting all the items in the array with indexes multiple of i to true. When i is 2, then the items 4, 6, 8 ... will be set to true. When i is 3, the items 6, 9, 12 ... will be set to true and so on.
And as you can deduce by the first if,
if ( sieve[i] == true ) continue;
... all the items that are true correspond to non-prime numbers.
I find the easiest way to understand something is to deconstruct it. Therefore, lets go through the loop a few times, shall we?
Dawn of the First Iteration
− 9999998 Values Remain −
i = 2
sieve[2] is false, so we keep going in the current iteration.
numberOfPrimes = 1 and thus we continue processing
Set every multiple of 2 to true in sieve[].
Dawn of the Second Iteration
− 9999997 Values Remain −
i = 3
sieve[3] is false, so we keep going in the current iteration.
numberOfPrimes = 2 and thus we continue processing
Set every multiple of 3 to true in sieve[].
Dawn of the Third Iteration
− 9999996 Values Remain −
i = 4
sieve[4] is true (from first iteration). Skip to next iteration.
etc... but in this case, the moon doesn't crash into Termina.
The loop in question isn't checking for true values, it's setting true values.
It's going through each multiple of the prime and marking it as non-prime up to maxLimit. You'll notice there's no other math in the code to determine what's prime and what's not.
This is the algorithm to find the prime numbers between 1 and the maximum limit given.
And the loop added 2nd is to make true for the number which is divisible by any other number. so for the first outer loop all the number divisible by two ll be set to true then divisible by 3 then by 4 and so on.. and the numbers for which the boolean array contains false are the prime numbers.

Categories