I was looking over this on YouTube and saw some code. I got most of it but didn't understand at all the reason why you the value n divide by two. Could someone please explain it?
import java.util.ArrayList;
public class Primes {
public static void main(String[] args) {
System.out.println(findPrimes(1, 100));
}
public static ArrayList<Integer> findPrimes(int start, int end) {
ArrayList<Integer> primes = new ArrayList<Integer>();
for(int n = start; n < end; n++) {
boolean prime = true;
int i = 2;
while(i <= n/2) {
if(n % i == 0) {
prime = false;
break;
}
i++;
}
if(prime) {
primes.add(n);
}
}
return primes;
}
}
A number can only be divided by a number that is less than or equal to its half. Or the number to be divided itself.
Here, we are checking till n/2 so that the number of iterations and the load on the system reduces and make the program more efficient. Since the greatest factor which can divide a number (excluding itself) is half of the number, we check only till that point. There is no point of checking beyond that.
It's an attempt to improve the efficiency of the solution by stopping the loop at a point where the algorithm will no longer find any more prime factors.
However, it's suboptimal. If n == a * b and a <= b, a can be no higher than the square root of n. Therefore, checking for i <= Math.sqrt(n) would eliminate many more unnecessary iterations of the loop for large values of n.
A further improvement could be made by iterating over known values of primes instead of incremental values of i, since once you've established that a number isn't divisible by 3 there's no point checking 6, 9, 12 and so on.
Related
I am attempting to solve a challenge, but I have hit a roadblock. I am a beginner programmer attempting to add tens of thousands of numbers. If I wait long enough, my program can easily yield the correct sum, however, I am looking for a more efficient method.
What is an efficient method for adding thousands of numbers quickly?
Side note: I have been reading about modular arithmetic, but I cannot quite wrap my head around it. Not sure if that could be useful for this situation.
I am attempting to get the sum of every prime number below 2 000 000. Here is my code so far:
public class Problem10 {
public static void main (String[] args) {
long sum = 0L;
for(long i = 1L; i < 2000000; i++) {
if(isPrimeNumber((int)i)) {
sum += i;
}
}
System.out.println(sum);
}
public static boolean isPrimeNumber(int i) {
int factors = 0;
int j = 1;
while (j <= i) {
if (i % j == 0) {
factors++;
}
j++;
}
return (factors == 2);
}
}
You can replace your isPrimeNumber() method with this to speed it up substantially.
public static boolean isPrimeNumber(int i) {
if (i==2) return true;
if (i==3) return true;
if (i%2==0) return false;
if (i%3==0) return false;
int j = 5;
int k = 2;
while (j * j <= i) {
if (i % j == 0) return false;
j += k ;
k = 6 - k;
}
return true;
}
This looks like homework, so I'm not going to give you the solution in code. The least you can do is code it yourself.
In your code, isPrimeNumber() is what's taking up most of the timeāif I had to guess, I would say 90-99% of it. What you can do to make it faster is implement the Sieve of Eratosthenes.
To start, you create an array that will hold all the prime numbers1. You should start it with a single value: 2. To find more prime numbers, iterate through every integer from 3 to the highest number you want. For each of those numbers, check if that number is divisible by any of the prime numbers in your array. If the next prime number in your array is greater than i / 2, you know that i is prime, and you can add it to your array.
After you have found all the prime numbers from 1 to n, the only way to sum them is by iterating through the array. That part cannot be optimized, but it will not take very long anyways.
1 There are two ways to do this. One is to just use an ArrayList or LinkedList, and add numbers as needed. The other is to create an array that is as large or larger than you need. As mentioned here, the number of primes equal to or less than n is less than (n / log(n)) * (1 + 1.2762 / log(n)), as long as n is greater than 598. If n is less than 598, you can just create an array of length 109.
In regards to the question in the title, "What is an efficient method for adding thousands of numbers quickly?", the only thing I can think of is multithreading. Create an array of all the numbers you want to sum, then have many threads sum different parts of the array. After that, sum all the results from each thread. This method will probably only be noticeably faster when summing huge amount of numbers, e.g. hundreds of thousands or millions.
I'm trying to get a program to get me the prime numbers from a certain range (user inputs the maximum number) and this variable called maxNumber will be used to stop the while loop. The control variable used starts at the first prime number 2 and is called i and will be used to print out the prime numbers (when found) and natural numbers, respectively.
My problem is that I'm not really sure if my algorithm inside the main method and mutator method are both correct and I have a problem where I am putting the user input (the max number) but nothing is happening at all after that -- basically, it is compiling and running but not responding when inputting the first variable.
Help would very much be appreciated !
import java.util.*;
public class PrimeCalculator {
private static int maxNumber;
private static int divisibleCount;
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
int i = 2;
System.out.println("Enter the maximum amount of numbers you want to find prime numbers within: ");
maxNumber = scanner.nextInt();
while(i <= maxNumber)
isPrime(i);
if(divisibleCount < 2)
System.out.println(i + " is a prime number");
if(divisibleCount > 2)
System.out.println(i + " is not a prime number.");
divisibleCount = 0;
i++;
}
public static void isPrime(int n) {
divisibleCount = 0;
for(int x = 1; x <= maxNumber; x++ )
if(n%x == 0)
divisibleCount++;
}
}
Although I do not think it is clear what you're asking, I will make a few suggestions.
First of all, at your main method, change if(divisibleCount < 2) to if(divisibleCount <= 2) because primes are divided by 1 and themselves (so, "divisibleCount" is 2).
Also, in your while loop, you should check if i equals one and say that it is not a prime.
As said in the comments, at the isPrime method , you can change the loop to for(int x = 1; x <=n; x++ ) as it is impossible for a number to be perfectly divided by soomething greater (i.e. 6 divided by 10 cannot have modulo 0)
EDIT: As dcsohl suggested, it is even better to have for(int x = 1; x <= Math.sqrt(n); x++) (see comment)
Check your syntax. At the while loop, you do not open and close brackets, so only isPrime(i) gets executed in the loop. Imagine
while(i <= maxNumber){
isPrime(i);
}
if(divisibleCount < 2) // ....etc
And since i is never incremented in the loop, it it always 2, so ... we have got an infinite loop!
(General improvement) Surround the maxNumber = scanner.nextInt(); in a try-catch block to avoid crashing when entering say, a string instead of an int.
These are the problems I found, hope I helped you.
PS. If you have any other question like this (i.e. general code checking), you should ask them at Code Review rather than Stack Overflow
I won't answer your Java questions, but the normal algorithm for enumerating the prime numbers is the Sieve of Eratosthenes, invented by a Greek mathematician over two thousand years ago:
function primes(n)
sieve := makeArray(2..n, True)
for p from 2 to n
if sieve[p]
output p # prime
for i from p*p to n step p
sieve[i] := False
This algorithm examines every number p from 2 to n; if p is prime, the loop on i marks False all the multiples of p; the i loop starts from the square of p because all smaller multiples will already have been marked False by smaller primes.
If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.
import java.io.*;
class Prime
{
public static void main(String args[])
{
long i,j,n=1000000100000L;
long sum=0;
long i1=1000000000000L;
long c;
System.out.println("The Prime Numbers are:");
for(i=i1;i<=n;i++)
{
c=0;
for(j=2;j<=10000000;j++)
{
if(i%j==0)
c=c+1;
if(c==1)
break;
}
if(c==0)
{
System.out.println(i);
sum=sum+i;
}
}
System.out.println("The Sum of Prime numbers are:"+sum);
}
}
This question already has answers here:
Project Euler #10 Java solution not working
(6 answers)
Closed 9 years ago.
I'm trying to find the sum of primes below millions. My code works when I try to find the sum of primes below hundred thousands but when I go large numbers it doesn't work. So I need some help to get this work for big numbers...
import java.util.Scanner;
public class sumPrime {
public static void main (String args []){
long n = 2000000; int i; int j;int sum =0;
for (i=2; i <n; i++){
for (j=2; j<i; j++){
if (i%j==0){
break;
}
}
if (i==j){
sum +=i;
}
}
System.out.print(sum);
}
}
Your code could be improved by making the inner loop stop earlier. If a number N is not prime, then it must have at least one factor (apart from 1) that is less or equal to sqrt(N). In this case, this simple change should make the program roughly 1000 times faster.
For a simple and (more) efficient algorithm, read up on the Sieve of Eratosthenes.
Bug - your sum needs to be a long. An int will probably overflow.
Note that the classic formulation of Sieve of Eratosthenes needs a large array of booleans (or a bitmap) whose size depends on the largest prime candidate you are interested in. In this case that means a 2Mbyte array (or smaller if you use a bitmap) ... which is too small to worry about. Also, you can reduce the memory usage by sieving in stages, though it makes the code more complicated.
Rather than trying to divide by all the numbers below i you could potentially keep the found prime numbers in a list and try to divide by those prime numbers (since any non prime number will be divisible by a prime number less than that).
public static long sumPrime2() {
List<Long> primes = new ArrayList<>();
primes.add(2L);
primes.add(3L);
long primeSum = 5;
for (long primeCandidate = 5; primeCandidate < 2000000; primeCandidate = primeCandidate + 2) {
boolean isCandidatePrime = true;
double sqrt = Math.sqrt(primeCandidate);
for (int i = 0; i < primes.size(); i++) {
Long prime = primes.get(i);
if (primeCandidate % prime == 0) {
isCandidatePrime = false;
break;
}
if (prime > sqrt) {
break;
}
}
if (isCandidatePrime) {
primes.add(primeCandidate);
primeSum += primeCandidate;
}
System.out.println(primeCandidate);
}
System.out.println(primes.size());
return primeSum;
}
This gave the answer in 8 seconds
I suspect integer overflow in i, j, sum - try making them all longs. In the sample code you shouldn't be getting overflows as Java ints are meant to be 32 bit but at some stage you certainly will.
As already mentioned - i only needs to iterate to the square root of n. So I would replace this line:
for (i=2; i <n; i++){
With:
long limit=sqrt(n);
for (i=2; i <limit; i++){
Note that calculating the square root outside the program loops will also speed things up a bit.
Also the sieve algorithm would be faster but requires Java to create an array containing n elements and at some stage that is going to fail with insufficient memory.
The best algorithm for this program uses the Sieve of Eratosthenes:
function sumPrimes(n)
sum, sieve := 0, makeArray(2..n, True)
for p from 2 to n
if sieve[p]
sum := sum + p
for i from p*p to n step p
sieve[i] := False
return sum
Then sumPrimes(2000000) returns the sum of the primes less than two million, in about a second. I'll leave it to you to translate to Java, with an appropriate data type for the sum. If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.
Problem 10 from Project Euler:
The program runs for smaller numbers and slows to a crawl in the hundred thousands.
At 2 million, an answer fails to show up even though the program seems like it is still running.
I'm trying to implement the Sieve of Eratosthenes. It is supposed to be very fast. What's wrong with my approach?
import java.util.ArrayList;
public class p010
{
/**
* The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17
* Find the sum of all the primes below two million.
* #param args
*/
public static void main(String[] args)
{
ArrayList<Integer> primes = new ArrayList<Integer>();
int upper = 2000000;
for (int i = 2; i < upper; i++)
{
primes.add(i);
}
int sum = 0;
for (int i = 0; i < primes.size(); i++)
{
if (isPrime(primes.get(i)))
{
for (int k = 2; k*primes.get(i) < upper; k++)
{
if (primes.contains(k*primes.get(i)))
{
primes.remove(primes.indexOf(k*primes.get(i)));
}
}
}
}
for (int i = 0; i < primes.size(); i++)
{
sum += primes.get(i);
}
System.out.println(sum);
}
public static boolean isPrime(int number)
{
boolean returnVal = true;
for (int i = 2; i <= Math.sqrt(number); i ++)
{
if (number % i == 0)
{
returnVal = false;
}
}
return returnVal;
}
}
You appear to be trying to implement the Sieve of Eratosthenes which should perform better that O(N^2) (In fact, Wikipedia says it is O(N log(log N)) ...).
The fundamental problem is your choice of data structure. You've chosen to represent the set of remaining prime candidates as an ArrayList of primes. This means that your test to see if a number is still in the set takes O(N) comparisons ... where N is the number of remaining primes. Then you are using ArrayList.remove(int) to remove the non-primes ... which is O(N) also.
That all adds up to making your Sieve implementation worse than O(N^2).
The solution is to replace the ArrayList<Integer> with an boolean[] where the positions (indexes) in the boolean array represent the numbers, and the value of the boolean says whether the number is prime / possibly prime, or not prime.
(There were other problems too that I didn't notice ... see the other answers.)
There are a few issues here. First, lets talk about the algorithm. Your isPrime method is actually the very thing that the sieve is designed to avoid. When you get to a number in the sieve, you already know it's prime, you don't need to test it. If it weren't prime, it would already have been eliminated as a factor of a lower number.
So, point 1:
You can eliminate the isPrime method altogether. It should never return false.
Then, there are implementation issues. primes.contains and primes.remove are problems. They run in linear time on an ArrayList, because they require checking each element or rewriting a large portion of the backing array.
Point 2:
Either mark values in place (use boolean[], or use some other more appropriate data structure.)
I typically use something like boolean primes = new boolean[upper+1], and define n to be included if !(primes[n]). (I just ignore elements 0 and 1 so I don't have to subtract indices.) To "remove" an element, I set it to true. You could also use something like TreeSet<Integer>, I suppose. Using boolean[], the method is near-instantaneous.
Point 3:
sum needs to be a long. The answer (roughly 1.429e11) is larger than the maximum value of an integer (2^31-1)
I can post working code if you like, but here's a test output, without spoilers:
public static void main(String[] args) {
long value;
long start;
long finish;
start = System.nanoTime();
value = arrayMethod(2000000);
finish = System.nanoTime();
System.out.printf("Value: %.3e, time: %4d ms\n", (double)value, (finish-start)/1000000);
start = System.nanoTime();
value = treeMethod(2000000);
finish = System.nanoTime();
System.out.printf("Value: %.3e, time: %4d ms\n", (double)value, (finish-start)/1000000);
}
output:
Using boolean[]
Value: 1.429e+11, time: 17 ms
Using TreeSet<Integer>
Value: 1.429e+11, time: 4869 ms
Edit:
Since spoilers are posted, here's my code:
public static long arrayMethod(int upper) {
boolean[] primes = new boolean[upper+1];
long sum = 0;
for (int i = 2; i <=upper; i++) {
if (!primes[i]) {
sum += i;
for (int k = 2*i; k <= upper; k+=i) {
primes[k] = true;
}
}
}
return sum;
}
public static long treeMethod(int upper) {
TreeSet<Integer> primes = new TreeSet<Integer>();
for (int i = 2; i <= upper; i++) {
primes.add(i);
}
long sum = 0;
for (Integer i = 2; i != null; i=primes.higher(i)) {
sum += i;
for (int k = 2*i; k <= upper; k+=i) {
primes.remove(k);
}
}
return sum;
}
Two things:
Your code is hard to follow. You have a list called "primes", that contains non prime numbers!
Also, you should strongly consider whether or not an array list is appropriate. In this case, a LinkedList would be much more efficient.
Why is this? An array list must constantly resize an array by: asking for new memory to create an array, then copying the old memory over in the newly created array. A Linked list would just resize the memory by changing a pointer. This is a lot quicker! However, I do not think that by making this change you can salvage your algorithm.
You should use an array list if you need to access the items non-sequentially, here, (with a suitable algorithm) you need to access the items sequentially.
Also, your algorithm is slow.Take the advice of SJuan76 (or gyrogearless), thanks sjuan76
The key to the efficiency of classic implementation of the sieve of Eratosthenes on modern CPUs is the direct (i.e. non-sequential) memory access. Fortunately, ArrayList<E> does implement RandomAccess.
Another key to the sieve's efficiency is its conflation of index and value, just like in integer sorting. Actually removing any number from the sequence destroys this ability to directly address without any computations. We must mark, not remove, any composite as we find them, so any numbers greater than it will remain in their places in the sequence.
ArrayList<Integer> can be used for that (except taking more memory than is strictly necessary, but for 2 million this is inconsequential).
So your code with a minimal edit fix (also changing sum to be long as others point out too), becomes
import java.util.ArrayList;
public class Main
{
/**
* The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17
* Find the sum of all the primes below two million.
* #param args
*/
public static void main(String[] args)
{
ArrayList<Integer> primes = new ArrayList<Integer>();
int upper = 5000;
primes.ensureCapacity(upper);
for (int i = 0; i < upper; i++) {
primes.add(i);
}
long sum = 0;
for (int i = 2; i <= upper / i; i++) {
if ( primes.get(i) > 0 ) {
for (int k = i*i; k < upper ; k+=i) {
primes.set(k, 0);
}
}
}
for (int i = 2; i < upper; i++) {
sum += primes.get(i);
}
System.out.println(sum);
}
}
Finds the result for 2000000 in half a second on Ideone. The projected run time for your original code there: between 10 and 400 hours (!).
To find rough estimates for the run time when faced with a slow code, you should always try to find out its empirical orders of growth: run it for some small size n1, then a bigger size n2, record the run times t1 and t2. If t ~ n^a, then a = log(t2/t1) / log(n2/n1).
For your original code the empirical orders of growth measured on 10k .. 20k .. 40k range of upper limit value N, are ~ N^1.7 .. N^1.9 .. N^2.1. For the fixed code it's faster than ~ N (in fact, it's ~ N^0.9 in the tested range 0.5 mln .. 1 mln .. 2 mln). The theoretical complexity is O(N log (log N)).
Your program is not the Sieve of Eratosthenes; the modulo operator gives it away. Your program will be O(n^2), where a proper Sieve of Eratosthenes is O(n log log n), which is essentially n. Here's my version; I'll leave it to you to translate to Java with appropriate numeric datatypes:
function sumPrimes(n)
sum := 0
sieve := makeArray(2..n, True)
for p from 2 to n step 1
if sieve[p]
sum := sum + p
for i from p * p to n step p
sieve[i] := False
return sum
If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.
In the following snippet from https://github.com/nayuki/Project-Euler-solutions/blob/master/p003.java :
private static long smallestFactor(long n) {
for (long i = 2, end = Library.sqrt(n); i <= end; i++) {
if (n % i == 0)
return i;
}
return n; // Prime
}
I was a bit confused with the return n part. Is n going to assume the value of i after it's returned in the if statement? Why?
No. It returns the unchanged parameter to indicate that it is prime.
If it is not prime, it returns the factor that shows it is not prime.
lets take a num.
num is divisible upto its half (i.e factors)
Implement Sieve of Eratosthenes for finding prime_numbers. It's an efficient process for finding Prime numbers. And then check whether the returned primes divide the "num" or not...