Project Euler Number 3 - java

First of all, this isn't homework... working on this outside of class to get some practice with java.
public class Problem3 {
public static void main(String[] args) {
int n = 13195;
// For every value 2 -> n
for (int i=2; i < n; i++) {
// If i is a multiple of n
if (n % i == 0) {
// For every value i -> n
for (int j=2; j < i; j++) {
if (n % j != 0) {
System.out.println(i);
break;
}
}
}
}
}
}
I keep modifying the code to try to make it do what I want.
As the problem says, you should be getting 5, 7, 13 and 29.
I get these values, plus 35, 65, 91, 145, 203, 377, 455, 1015, 1885, and 2639. I think I'm on the right track as I have all the right numbers... just have a few extras.
And in checking a few of the numbers in both being divisible by n and being prime numbers, the issue here is that the extra numbers aren't prime. Not sure what's going on though.
If anyone has any insight, please share.

This part
for (int j=2; j < i; j++) {
if (n % j != 0) {
System.out.println(i);
break;
}
doesn't check whether i is prime. Unless i is small, that will always print i at some point, because there are numbers smaller than i that don't divide n. So basically, that will print out all divisors of n (It wouldn't print the divisor 4 for n == 12, for example, but that's an exception).
Note also that the algorithm - using long instead of int to avoid overflow - even if fixed to check whether the divisor i is prime for deciding whether to print it, will take a long time to run for the actual target. You should investigate to find a better algorithm (hint: you might want to find the complete prime factorisation).

I solved this problem in Java and looking at my solution the obvious advice is start using BigInteger, look at the documentation for java.math.BigInteger
Also a lot of these problems are "Math" problems as much as they are "Computer Science" problems so research the math more, make sure you understand the math reasonably well, before coming up with your algorithm. Brute force can work some times, but often there are tricks to these problems.

Brut force can also work for checking whether factor is prime or not for this problem...
eg.
for(i=1;i<=n;i++)// n is a factor.
{
for(j=i;j>=1;j--)
{
if(i%j==0)
{
counter++;// set counter=0 befor.
}
if(counter==2) // for a prime factor the counter will always be exactly two.
{
System.out.println(i);
}
counter=0;
}
}

Don't know about Java but here is my C code if it is of any help.
# include <stdio.h>
# include <math.h>
// A function to print all prime factors of a given number n
void primeFactors(long long int n)
{
// Print the number of 2s that divide n
while (n%2 == 0)
{
printf("%d ", 2);
n = n/2;
}
int i;
// n must be odd at this point. So we can skip one element (Note i = i +2)
for ( i = 3; i <= sqrt(n); i = i+2)
{
// While i divides n, print i and divide n
while (n%i == 0)
{
printf("%d ", i);
n = n/i;
}
}
// This condition is to handle the case whien n is a prime number
// greater than 2
if (n > 2)
printf ("%ld ", n);
}
/* Driver program to test above function */
int main()
{
long long int n = 600851475143;
primeFactors(n);
return 0;
}

Its very good that you are working on such problems out of class.
Saw your code. You are writing a procedural code inside main function/thread.
Instead write functions and think step by step algorithmically first.
The simple algorithm to solve this problem can be like this:
1) Generate numbers consecutively starting from 2 which is the least prime, to 13195/2. (Any number always has its factor smaller than half of it's value)
2) Check if the generated number is prime.
3) If the number is prime then check if it is factor of 13195;
4) Return the last prime factor as it is going to be the largest prime factor of 13195;
One more advice is try writting seperate functions to avoid code complexity.
Code is like this...
public class LargestPrimeFactor {
public static long getLargestPrimeFactor(long num){
long largestprimefactor = 0;
for(long i = 2; i<=num/2;i++){
if(isPrime(i)){
if(num%i==0){
largestprimefactor = i;
System.out.println(largestprimefactor);
}
}
}
return largestprimefactor;
}
public static boolean isPrime(long num){
boolean prime=false;
int count=0;
for(long i=1;i<=num/2;i++){
if(num%i==0){
count++;
}
if(count==1){
prime = true;
}
else{
prime = false;
}
}
return prime;
}
public static void main(String[] args) {
System.out.println("Largest prime factor of 13195 is "+getLargestPrimeFactor(13195));
}
}

Related

This code runs and compiles but nothing happens when I enter a very large number. (Euler project, problem 3)

I'm a newbie.
So I've been doing the project Euler problems to sharpen my java skills and I got past the first 2. I'm stuck on the third one. It says :
"The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?"
I wrote the following code:
public class Exercise {
public static void main(String[] args) {
long a = 600851475143L;
long i = 1;
boolean isPrime = true;
long currentNum = 0;
while (i <= a) {
if (a % i == 0) {
for (long j = 1; j < a; j++) {
if (a == i || a % j == 0) {
isPrime = false;
} else {
currentNum = i;
}
}
}
i++;
}
System.out.println("the largest prime factor of " + a + " is " + currentNum);
}
}
It works perfectly for smaller numbers like 10,20,55,100,560523 etc but when I enter a large number like 600851475143L, the code compiles and runs but nothing happens.
Any help appreciated, thanks !
Look at your a variable. It's 600851475143L.
That means that your processor has to do up to 600851475143 loop cycles, based on your condition:
while (i <= a) {
i++;
}
I do not take into consideration the code inside the while() loop, but even without it that is too much, even for modern computers :)
If you want to calculate prime factors of numbers of that range... you should consider using some more efficient ways than simple iteration.
You have nested conditions, executions of which will hop CPU.
while (i <= a) {// This condition will be executed 600851475143 times
if (a % i == 0) {
for (long j = 1; j < a; j++) {// This condition will be executed 600851475143 times
So far a=600851475143, code will execute 600851475143*600851475143 times. That's why you don't see output as CPU is busy executing so many conditions.
Also reason you saw output for a=100 because for this input number of iterations = 100*100 which won't take much time on any modern machine
public class Exercise {
public static void main(String[] r)
{
try{
long a = 600851475143L;
System.out.println("the largest prime factor of " + a+ " is " +largestPrimeFactor(a) );
}catch(Exception e)
{
e.printStackTrace();
}
}
public static int largestPrimeFactor(long number) {
int i;
long copyOfInput = number;
for (i = 2; i <= copyOfInput; i++) {
if (copyOfInput % i == 0) {
copyOfInput /= i;
i--;
}
}
return i;
}
}
Try this one
The answer given by Pavel Smirnov is correct. Actually, the code is running for value 600851475143L as well. It's just that the input number is huge so the code is taking hell lot of time to finish. Even the code is not in the deadlocked state. Still, to prove the point to you, you can add a log in the inner-loop body like:
System.out.println("Testing Prime for Number :"+j);
in the inner-loop for (long j = 1; j < a; j++){}
Doing this, you will see that the code is actually running.
P.S.: This algorithm will loop 600851475143L * 600851475143L times, which is really time-consuming.

Java throwing division by zero error?

In an attempt to relearn how to write code in Java I've been going through some problems from Project Euler. The following code I've written is to solve problem 3: finding the largest prime factor of the number 600851475143.
public class ProjectEuler {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ProjectEuler t = new ProjectEuler();
System.out.println(t.findLargestPrime(600851475143L));
}
public Boolean isPrime(int x) {
Boolean answer = true;
for (int i = 2; i < x/2; i++) {
if (x%i == 0) {
answer = false;
}
}
return answer;
}
public int findLargestPrime(Long max) {
int largest = 1;
for (int i = 2 ; i < max/2; i++) {
if (max%i == 0 && isPrime(i) && i > largest) {
largest = i;
}
}
return largest;
}
}
However, when I run it the code throws an arithmetic error because I'm trying to divide by zero? The actual error message is shown here:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at projecteuler.ProjectEuler.findLargestPrime(ProjectEuler.java:37)
at projecteuler.ProjectEuler.main(ProjectEuler.java:19)
I don't know if I've made a stupid mistake somewhere or if it's a quirk of Java that I don't understand? Could anyone shed some light on this?
Thank you.
for (int i = 2 ; i < max/2; i++) will eventually overflow (because 600851475143 / 2 is bigger than Integer.MAX_VALUE) and eventually i will equal to 0 when it will happen max%i will throw that exception.
Change i to long if you want to prevent it from happeninng (you should also change all the other int's to long).
This is not an answer to the actual question, but: You do not have to check all the numbers up to max, and you do not even have to do any checks whether a divisor is prime. You just have to (repeatedly) divide the max by any divisor i you found.
long l = 600851475143L;
for (int i = 2; i <= Math.sqrt(l); i++) {
if (l % i == 0) {
System.out.println(i);
l /= i;
i--;
}
}
System.out.println("--> " + l);
This way, you know that this divisor must be prime -- if it were composite, max would already have been divided by its components. This also means that you do not have to loop all the way up to max (which, for the given value, would take a really long time), but only up to the largest prime divisor, which might be much much smaller. And once you reach sqrt(l) -- for the current value of l, not the original! -- you can stop, since there can not be any divisors higher than that, and the remaining value of l will be the final (and thus, largest) prime factor.
Thus, this reduces the complexity from about O(n²) to about O(n½).

How to optimize algorithm to be able to determine 10 digit long prime numbers in java

I am currently new to java and programming in general, I'm working on an algorithm that determines the prime numbers in specific given ranges. Currently it works with six ranges which are numbers under 1 billion, when I tried to determine a 10 digit long number it failed. I am aware it needs to be changed to long since the digit is out of range but I am not sure how.
this is the part of the code where it determines if the umber is prime:
public ArrayList<Integer> getPrimes(int StartPos, int n) {
ArrayList<Integer> primeList = new ArrayList<>();
boolean[] primes = new boolean[n + 1];
for (int i = StartPos; i < primes.length; i++) {
primes[i] = true;
}
int num = 2;
while (true) {
for (int i = 2;; i++) {
int m = num * i;
if (m > n) {
break;
} else {
primes[m] = false;
}
}
boolean nextNum = false;
for (int i = num + 1; i < n + 1; i++) {
if (primes[i]) {
num = i;
nextNum = true;
break;
}
}
if (!nextNum) {
break;
}
}
for (int i = 0; i < primes.length; i++) {
if (primes[i]) {
primeList.add(i);
}
}
return primeList;
}
I was checking online and found that perhaps I could do it with vectors but I have no experience with them and Also they are relatively slower than an Array.
You might try BigInteger#isProbablePrime: https://www.tutorialspoint.com/java/math/biginteger_isprobableprime.htm
import java.math.BigInteger;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
// Java 8
public class FindPrimes {
public static void main(String[] args) {
System.out.println("1 - 100 primes: " + findPrimes(1L, 99L));
System.out.println("some 10-digit primes: " + findPrimes(99_999_999_999L, 20000L));
}
private static List<Long> findPrimes(long start, long quant) {
return LongStream.rangeClosed(start, start + quant).filter(v ->
BigInteger.valueOf(v).isProbablePrime(1)).boxed().collect(Collectors.toList());
}
}
You say you are learning, so I will give you an outline in pseudocode, not the answer.
In general the method to find a prime in a range is:
repeat
pick a number in the range
until (the number is prime)
You want a ten digit number. One way to generate a candidate while avoiding obvious non-primes is:
start with digit in [1..9] // No leading zero.
repeat 8 times
append a digit in [0..9]
endrepeat
append a digit in [1, 3, 7, 9] // Final digits for large primes.
That will give you a ten digit possible prime.
Now you need to test to check it is prime.
There are tests like Miller-Rabin that you could try, but probably not if you are a real beginner. I would suggest setting up a Sieve of Eratosthenes covering numbers to to 10,000 which is the square root of your upper limit of 10,000,000,000. That will give you fast access to all the primes below the square root of your number. Set up the sieve once only at the start of your program. Make it a separate Class, and include a int nextPrime(int n) method which returns the next prime after the supplied parameter. Once that is in place, then you can write a trial division method to test your ten digit number:
boolean method isPrime(tenDigitNumber)
testPrime <- 2
limit <- square root of tenDigitNumber // Only calculate this once.
while (testPrime < limit)
if (tenDigitNumber MOD testPrime == 0)
return false // Number is not prime.
else
testPrime <- sieve.nextPrime(testPrime)
endif
endwhile
return true // If we get here then the number is prime.
end isPrime
Because you have set up the sieve in advance, this should run reasonably quickly. If it is too slow, then it is time to look at coding Miller-Rabin or one of the other heavy-duty prime test methods.
As well as the Sieve of Eratosthenes class, another useful utility method is an iSqrt() method that returns an integer square root. My own version uses the Newton-Raphson method, though no doubt there are other possibilities.

Prime numbers finder

So I'm trying to make a method that finds a random prime number from 0 to n(inputed from user) using the RandomGenerator class from the acm.utils package and for some reason it doesn't work! I've thought it through lots of times and I think this solution is right, bot it ends up giving numbers that are not wrong!
This is for a project at the uni and I have to use only acm.util! no scanners! only this kind of code
public int nextPrime(int n){
int num = rgen.nextInt(1, n);
boolean prime=false;
if (num==1){
return (num);
}else{
int i = 2;
int c = 0;
while ((i < num-1)&&(prime=false)){
if( (num % i) == 0){
c=c+1;
}
if((c==0)&&(i==(num-1))){
prime=true;
}
if(c>=1){
num = rgen.nextInt(1, n);
i=1;
}
i=i+1;
}
}
return (num);
}
= is for assignment and == is for comparison.
You need to change your condition
while ((i < num-1)&&(prime=false)){
to
while ((i < num-1)&&(prime==false)){ or
while ((i < num-1)&&(!prime)){
Here is a basic method to determine if a number is prime or not. This method is really only meant to understand the logic behind finding if a number is prime or not. Enjoy.
public boolean isPrime()
{
boolean prime = true;
for (int s = 2; s < original; s++)
if (original % s != 0 )
{
prime = true;
}
else
{
prime = false;
return prime;
}
return prime;
Your code is rather bizarre. Variable like c is not very clear, and the name doesnt help.
You could read other implementations.
I made some change to make it work. Traces help too !
public static int nextPrime(int n)
{
int num = (int)(1+Math.random()*n); // other generator
// TRACE HERE
System.out.println("START:"+num);
boolean prime=false;
// CHANGE HERE
if (num==2)
{
return (num);
}
else
{
int i = 2;
int c = 0;
// CHANGE HERE
while ((i < num-1)&&(prime==false))
{
// Not prime => next one
if( (num % i) == 0)
{
// TRACE HERE
System.out.println("YOU LOSE: :"+num+" divided by "+i);
c=c+1;
}
if((c==0)&&(i==(num-1)))
{
prime=true;
// TRACE HERE
System.out.println("BINGO:"+num);
// CHANGE HERE
break;
}
if(c>=1)
{
// SAME PLAYER LOOP AGAIN
num = (int)(1+Math.random()*n);
// TRACE HERE
System.out.println("RESTART:"+num);
i=1;
// CHANGE HERE
c=0;
}
i=i+1;
}
}
return (num);
}
Either you have misstated the problem or else you have not come close to coding the problem correctly. There are 4 prime numbers up to 10: {2,3,5,7}. If the user enters 10, should you give a random prime from this set, or a random one of the first 10 primes {2,3,5,7,11,13,17,19,23,29}? You said the problem was the first interpretation (where 11 would not be a valid response to 10) but you implemented an attempt at the second interpretation (where 11 would be a valid response to 10).
There is a simple way to generate a prime number uniformly within the primes in the range [1,1000000], say. Choose a random integer in the range and test whether it is prime. If so, return it. If not, repeat. This is called rejection sampling. It is quite complicated to get a uniformly random prime number without rejection sampling, since it's not easy to count or list the prime numbers in a large range. It is relatively easy to test whether a number is prime, and for n>1 it only takes about log n samples on average to find a prime in [1,n].

Optimizing recursive method

I have some code that needs to run with some rather large numbers, and it involves incrementing into a recursive method and is therefor very slow to the point where I can't even get to my desired answer. Could someone help me optimize it? I am a beginner though, so I can't do anything very complex/difficult.
public class Euler012{
public static void main(String[]args){
int divisors=0;
for(long x=1;divisors<=501;x++){
divisors=1;
long i=triangle(x);
for(int n=1;n<=i/2;n++){
if(i%n==0){
divisors++;
}
}
//System.out.println(divisors+"\n"+ i);
System.out.println(i+": " + divisors);
}
}
public static long triangle(long x){
long n=0;
while(x>=0){
n+=x;
x--;
triangle(x);
}
return n;
}
}
First: i don't think its an optimization problem, because its a small task, but as mentioned in the comments you do many unnecessary things.
Ok, now lets see where you can optimize things:
recursion
recursion has usually a bad performance, especially if you don't save values this would be possible in your example.
e.g.: recursive triangle-number function with saving values
private static ArrayList<Integer> trianglenumbers = new ArrayList<>();
public static int triangleNumber(int n){
if(trianglenumbers.size() <= n){
if(n == 1)
trianglenumbers.add(1);
else
trianglenumbers.add(triangleNumber(n-1) + n);
}
return trianglenumbers.get(n-1);
}
but as mentioned by #RichardKennethNiescior you can simply use the formula:
(n² + n)/2
but here we can do optimization too!
you shouldnt do /2 but rather *0.5 or even >>1(shift right)
but most compilers will do that for you, so no need to make your code unreadable
your main method
public static void main(String[]args){
int divisors = 0; //skip the = 0
for(long x=1;divisors<=501;++x){ // ++x instead of x++
divisors=0;
long i=(x*x + x) >> 1; // see above, use the one you like more
/*how many divisors*/
if(i == 1) divisors = 1;
else{ /*1 is the only number with just one natural divisor*/
divisors = 2; // the 1 and itself
for(int n = 2; n*n <= i; ++n){
if(n*n == i) ++divisors;
else if(i%n == 0) divisors += 2;
}
}
System.out.println(i+": " + divisors);
}
}
the ++x instead of x++ thing is explained here
the how many divisors part:
every number except 1 has at least 2 divisors (primes, the number itself and one)
to check how many divisors a number has, we just need to go to the root of the number
(eg. 36 -> its squareroot is 6)
36 has 9 divisors (4 pares) {1 and 36, 2 and 18, 3 and 12, 4 and 8, 6 (and 6)}
1 and 36 are skiped (for(**int n = 2**)) but counted in divisors = 2
and the pares 2, 3 and 4 increase the number of divisors by 2
and if its a square number (n*n == i) then we add up 1
You dont have to generate a new triangle number from scratch each time, if you save the value to a variable, and then add x to it on the next iteration, you dont really need to have the triangle method at all.

Categories

Resources