Prime Factorization With Java and Finding an Upper Bound - java

Here is what I am looking to do. I have listed my code below for your reference. Thank you in advance for any help you can provide.
Goal: Find Prime Factorizations of a number n. Then concatenate the prime factors into one number, x. Then Take that number, x, and divide by n. If x%n = 0, print True. If x%n != 0, print false. (i.e. if n = 100, Prime Factors are 2,2,5,5. Turn into 2255, then take 2255/100. 2255%100 != 0, Print False. )
What I have now prints out the prime factors correctly for some numbers, but when I try to use another prime number, the program will quit. Also, If I use a number like 123, it will only print out 3, not 3 and 41. Do you have any suggestions?
If possible, ideally I would like to run this for numbers j= 2 through any upper bound I set, call the upper bound U, and if any value for j = 2 through U yields a result that is true (from above) Then I would like to print that j value.
import acm.program.*;
import acm.util.*;
import java.util.Scanner;
import java.util.Arrays.*;
// -------------------------------------------------------------------------
public class FactorsLoop extends ConsoleProgram
{
//~ Instance/static variables .............................................
private RandomGenerator rgen = RandomGenerator.getInstance();
//~ Constructor ...........................................................
// ----------------------------------------------------------
/**
* Creates a new ForLoops object.
*/
public void run()
{
//
int n1 = 10000;
int n2 =(n1);
double U = 10000;
StringBuilder factors = new StringBuilder();
for (int j = 2; j < U; j++) {
for (int i = 2; i*i <= n1; i++) {
// if i is a factor of N, repeatedly divide it out
while (n1% i == 0) {
n1 = n1 / i;
factors.append(Integer.toString(i));
}
}
}
double newNumber = Integer.parseInt(factors.toString());
double x = (newNumber / n2);
print(x);
if ( newNumber % n2 == 0 ){
println(n2);
}
}
}

Your code correctly adds all those primes to factors which it divides out. However, it also should add n1 after the loop, should it happen to be != 1 (which will occur precisely when the power of the largest factor is 1).
The reason is the optimisation in your code whereby the inner loop is exited when the current factor exceeds sqrt(n1) (condition i*i <= n1 in the for loop header). This is a valid optimisation but like many optimisations it makes the logic more complicated and error-prone...
Note: the outer loop that iterates j does not seem to make any sense at all; it will only cause the small factors to be appended repeatedly. Get the inner loop into working shape, factor it out into a separate function (pun intended) and then use it to implement your ranged test which looks for the first result that satisfies some criterion.
For example, the function that returns the concatenated factors could look like this:
public string concatenated_factors (int n)
{
StringBuilder result = new StringBuilder();
for (int i = 2; i * i <= n; ++i)
for ( ; n % i == 0; n /= i)
result.append(Integer.toString(i));
if (n != 1)
result.append(Integer.toString(n));
return result.toString();
}
Note: I'm not familiar with Java, so some specifics may be a bit fuzzy here.

Related

How to find the 5th perfect number (which is 33550336)? The problem is taking forever to run

I am trying to write a Java method that checks whether a number is a perfect number or not.
A perfect number is a number that is equal to the sum of all its divisor (excluding itself).
For example, 6 is a perfect number because 1+2+3=6. Then, I have to write a Java program to use the method to display the first 5 perfect numbers.
I have no problem with this EXCEPT that it is taking forever to get the 5th perfect number which is 33550336.
I am aware that this is because of the for loop in my isPerfectNumber() method. However, I am very new to coding and I do not know how to come up with a better code.
public class Labreport2q1 {
public static void main(String[] args) {
//Display the 5 first perfect numbers
int counter = 0,
i = 0;
while (counter != 5) {
i++;
isPerfectNumber(i);
if (isPerfectNumber(i)) {
counter++;
System.out.println(i + " ");
}
}
}
public static boolean isPerfectNumber(int a) {
int divisor = 0;
int sum = 0;
for (int i = 1; i < a; i++) {
if (a % i == 0) {
divisor = i;
sum += divisor;
}
}
return sum == a;
}
}
This is the output that is missing the 5th perfect number
Let's check the properties of a perfect number. This Math Overflow question tells us two very interesting things:
A perfect number is never a perfect square.
A perfect number is of the form (2k-1)×(2k-1).
The 2nd point is very interesting because it reduces our search field to barely nothing. An int in Java is 32 bits. And here we see a direct correlation between powers and bit positions. Thanks to this, instead of making millions and millions of calls to isPerfectNumber, we will be making less than 32 to find the 5th perfect number.
So we can already change the search field, that's your main loop.
int count = 0;
for (int k = 1; count < 5; k++) {
// Compute candidates based on the formula.
int candidate = (1L << (k - 1)) * ((1L << k) - 1);
// Only test candidates, not all the numbers.
if (isPerfectNumber(candidate)) {
count++;
System.out.println(candidate);
}
}
This here is our big win. No other optimization will beat this: why test for 33 million numbers, when you can test less than 100?
But even though we have a tremendous improvement, your application as a whole can still be improved, namely your method isPerfectNumber(int).
Currently, you are still testing way too many numbers. A perfect number is the sum of all proper divisors. So if d divides n, n/d also divides n. And you can add both divisors at once. But the beauty is that you can stop at sqrt(n), because sqrt(n)*sqrt(n) = n, mathematically speaking. So instead of testing n divisors, you will only test sqrt(n) divisors.
Also, this means that you have to start thinking about corner cases. The corner cases are 1 and sqrt(n):
1 is a corner case because you if you divide n by 1, you get n but you don't add n to check if n is a perfect number. You only add 1. So we'll probably start our sum with 1 just to avoid too many ifs.
sqrt(n) is a corner case because we'd have to check whether sqrt(n) is an integer or not and it's tedious. BUT the Math Overflow question I referenced says that no perfect number is a perfect square, so that eases our loop condition.
Then, if at some point sum becomes greater than n, we can stop. The sum of proper divisors being greater than n indicates that n is abundant, and therefore not perfect. It's a small improvement, but a lot of candidates are actually abundant. So you'll probably save a few cycles if you keep it.
Finally, we have to take care of a slight issue: the number 1 as candidate. 1 is the first candidate, and will pass all our tests, so we have to make a special case for it. We'll add that test at the start of the method.
We can now write the method as follow:
static boolean isPerfectNumber(int n) {
// 1 would pass the rest because it has everything of a perfect number
// except that its only divisor is itself, and we need at least 2 divisors.
if (n < 2) return false;
// divisor 1 is such a corner case that it's very easy to handle:
// just start the sum with it already.
int sum = 1;
// We can stop the divisors at sqrt(n), but this is floored.
int sqrt = (int)Math.sqrt(n);
// A perfect number is never a square.
// It's useful to make this test here if we take the function
// without the context of the sparse candidates, because we
// might get some weird results if this method is simply
// copy-pasted and tested on all numbers.
// This condition can be removed in the final program because we
// know that no numbers of the form indicated above is a square.
if (sqrt * sqrt == n) {
return false;
}
// Since sqrt is floored, some values can still be interesting.
// For instance if you take n = 6, floor(sqrt(n)) = 2, and
// 2 is a proper divisor of 6, so we must keep it, we do it by
// using the <= operator.
// Also, sqrt * sqrt != n, so we can safely loop to sqrt
for (int div = 2; div <= sqrt; div++) {
if (n % div == 0) {
// Add both the divisor and n / divisor.
sum += div + n / div;
// Early fail if the number is abundant.
if (sum > n) return false;
}
}
return n == sum;
}
These are such optimizations that you can even find the 7th perfect number under a second, on the condition that you adapt the code for longs instead of ints. And you could still find the 8th within 30 seconds.
So here's that program (test it online). I removed the comments as the explanations are here above.
public class Main {
public static void main(String[] args) {
int count = 0;
for (int k = 1; count < 8; k++) {
long candidate = (1L << (k - 1)) * ((1L << k) - 1);
if (isPerfectNumber(candidate)) {
count++;
System.out.println(candidate);
}
}
}
static boolean isPerfectNumber(long n) {
if (n < 2) return false;
long sum = 1;
long sqrt = (long)Math.sqrt(n);
for (long div = 2; div <= sqrt; div++) {
if (n % div == 0) {
sum += div + n / div;
if (sum > n) return false;
}
}
return n == sum;
}
}
The result of the above program is the list of the first 8 perfect numbers:
6
28
496
8128
33550336
8589869056
137438691328
2305843008139952128
You can find further optimization, notably in the search if you check whether 2k-1 is prime or not as Eran says in their answer, but given that we have less than 100 candidates for longs, I don't find it useful to potentially gain a few milliseconds because computing primes can also be expensive in this program. If you want to check for bigger perfect primes, it makes sense, but here? No: it adds complexity and I tried to keep these optimization rather simple and straight to the point.
There are some heuristics to break early from the loops, but finding the 5th perfect number still took me several minutes (I tried similar heuristics to those suggested in the other answers).
However, you can rely on Euler's proof that all even perfect numbers (and it is still unknown if there are any odd perfect numbers) are of the form:
2i-1(2i-1)
where both i and 2i-1 must be prime.
Therefore, you can write the following loop to find the first 5 perfect numbers very quickly:
int counter = 0,
i = 0;
while (counter != 5) {
i++;
if (isPrime (i)) {
if (isPrime ((int) (Math.pow (2, i) - 1))) {
System.out.println ((int) (Math.pow (2, i -1) * (Math.pow (2, i) - 1)));
counter++;
}
}
}
Output:
6
28
496
8128
33550336
You can read more about it here.
If you switch from int to long, you can use this loop to find the first 7 perfect numbers very quickly:
6
28
496
8128
33550336
8589869056
137438691328
The isPrime method I'm using is:
public static boolean isPrime (int a)
{
if (a == 1)
return false;
else if (a < 3)
return true;
else {
for (int i = 2; i * i <= a; i++) {
if (a % i == 0)
return false;
}
}
return true;
}

Perfect Number Performance

I have a solution for the Kattis Problem https://open.kattis.com/problems/almostperfect. The solution is accepted, but the runtime is too long (>1.00s).
I tried everything to solve this issue. What can I do to further improve the performance of my code?
import java.io.FileInputStream;
import java.util.Scanner;
import java.io.*;
import java.util.*;
public class almostperfect {
public static int perfect(int number){
// 2 = perfect
// 1 = almost perfect
// 0 = not perfect
int sum = 0;
int b = 0;
for(int i=1;i<number;i++)
{
if(number%i==0)
{
sum = sum + i;
}
}
if(sum == number){
b = 2;
} else if(Math.abs(sum-number)<=2){
b = 1;
}
return b;
}
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
ArrayList<Integer> input = new ArrayList<Integer>();
int a;
int status;
while(scan.hasNextLong()){
input.add((int) scan.nextLong());
}
for(int i=0; i<input.size(); i++){
a = input.get(i);
status = perfect(a);
if(status==2){
System.out.println(a+" perfect");
} else if (status==1){
System.out.println(a+" almost perfect");
} else {
System.out.println(a+" not perfect");
}
}
}}
When you calculate the divisors of number, you don't have to loop from 1 to number, but to the square root of number. Take 100 for example - if 2 is a dividor of 100, so is 100/2.
int sum = 1; //1 is always a divisor
int b = 0;
int sqr = (int)Math.sqrt(number);
for(int i=2;i< sqr;i++)
{
if(number%i==0)
{
sum = sum + i;
sum = sum + number/i;
}
}
//Check what happens for sqr - if it's a divisor, add it only once
if (sqr * sqr == number)
sum += sqr;
Your code is fine, what is not fine is the method of finding the factors for the number it implements. You need to be smarter than brute force checking every possible number smaller than number if it is a factor.
First, obviously 1 is always a factor, since any number divides by 1 without a remainder. Also, by definition the number itself is not a factor. This restricts factors to be found to the range (2 ... n-1).
Second, if you find a divisor, then the dividend is also a divisor:
dividend = number / divisor -> implies: dividend is also a divisor
This means divisors are always found in pairs (dividend is also a divisor, making the pair). The one exception that must be accounted for is that dividend may be the same as dividend (e.g. number = 9, divisor = 3 -> dividend = 3). This can be exploited, leading to:
Third, when starting testing from the smallest possible divisor (2), the first dividend you find is the largest divisor possible, with dividends decreasing steadily while you increase the tested divisor. This means there is no need to explicitly check for divisors that are found as dividend. That means the upper testing limit would be where divisor and dividend become equal, in other words the root of number.
As stated for the problem in the link, numbers may be in range 1 ... 1E9. Your brute force method needs 1 billion tests for 1E9, while the smart version exploiting above properties, only needs 31621. Thats about factor 30000 faster!

Java program taking forever to run with large numbers

I am writing a Java program that calculates the largest prime factor of a large number. But I have an issue with the program's complexity, I don't know what has caused the program to run forever for large numbers, it works fine with small numbers.
I have proceeded as follow :
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Largest_prime_factor {
public static void main(String[] args)
{
//ArrayList primesArray = new ArrayList();
ArrayList factorArray = new ArrayList();
long largest = 1;
long number = 600851475143L ;
long i, j, k;
//the array list factorArray will have all factors of number
for (i = 2; i < number; i++)
{
if( number % i == 0)
{
factorArray.add(i);
}
}
Here, the Array List will have all the factors of the number.
So I'll need to get only the prime ones, for that, I used a method that checks if a number is prime or not, if it's not a prime number, I remove it from the list using the following method :
java.util.ArrayList.remove()
So the next part of the code is as follow :
for (i = 2; i < number; i++)
{
if (!isPrime(i))
{
factorArray.remove(i);
System.out.println(factorArray);
}
}
System.out.println(Collections.max(factorArray));
}
The last line prints the largest number of factorArray, which is what I am looking for.
public static boolean isPrime(long n)
{
if(n > 2 && (n & 1) == 0)
return false;
for(int i = 3; i * i <= n; i += 2)
if (n % i == 0)
return false;
return true;
}
}
The function above is what I used to determine if the number is a prime or not before removing it from the list.
This program works perfectly for small numbers, but it takes forever to give an output for large numbers, although the last function is pretty fast.
At first, I used to check if a number is prime or not inside of the first loop, but it was even slower.
You are looping over 600851475143 numbers.
long number = 600851475143L ;
for (i = 2; i < number; i++)
Even if we assume that each iteration takes very very small time (as small as 1 microsecond), it'll still take days before the loop finishes.
You need to optimise your prime-finding logic in order for this program to run faster.
One way to reduce the iterations to reasonable number is to loop until square root of number.
for (i = 2; i < Math.sqrt(number); i++)
or
for (i = 2; i*i < number; i++)
The calculation of the prime factors of 600851475143L should take less than a milli-second (with a not totally inefficient algorithm). The main parts your code is currently missing:
The border should be sqrt(number) and not number.
The current value should be checked in a while-loop (to prevent that non-prime-factors are added to the list, reduces range to check).
The max. value should be decreased (as well as the border) to number/factor after finding a factor.
Further improvements are possible, e.g. to iterate only over non-even numbers (or only iterate over numbers that are neither a multiple of 2 and 3) etc.
An example implementation for the same question on codereview (link):
public static long largestPrimeFactor(
final long input) {
////
if (input < 2)
throw new IllegalArgumentException();
long n = input;
long last = 0;
for (; (n & 1) == 0; n >>= 1)
last = 2;
for (; n % 3 == 0; n /= 3)
last = 3;
for (long v = 5, add = 2, border = (long) Math.sqrt(n); v <= border; v += add, add ^= 6)
while (n % v == 0)
border = (long) Math.sqrt(n /= last = v);
return n == 1 ? last : n;
}
for (i = 2; i < number; i++)
{
if( number % i == 0)
{
factorArray.add(i);
}
}
For an large input size, you will be visiting up to the value of the number. Same for the loop of removing factors.
long number = 600851475143L ;
this is a huge number, and you're looping through this twice. Try putting in a count for every 10,000 or 100,000 (if i%10000 print(i)) and you'll get an idea of how fast it's moving.
One of the possible solutions is to only test if the the prime numbers smaller than the large number divide it.
So I checked
for (i=2; i < number; i++)
{
if(isPrime(i))
{
if( number % i == 0)
{
factorArray.add(i);
}
}
}
So here I'll only be dividing by prime numbers instead of dividing by all numbers smaller than 600851475143.
But this is still not fast, a complete modification of the algorithm is necessary to obtain an optimal one.
#Balkrishna Rawool suggestion is the right way to go. For that I would suggest to change the iteration like this: for (i = 3; i < Math.sqrt(number); i+=2) and handle the 2 manually. That will decrease your looping because none of the even numbers except 2 are prime.

Decrease execution time of the Java program

I wrote the following program for the second problem of project Euler, for the question: "Project Euler #3: Largest prime factor".It is supposed to print out all the highest prime factors of the provided inputs.
import java.util.Scanner;
public class euler_2 {
public static boolean isPrime(int n) {
if (n % 2 == 0) return false;
for (int i = 3; i * i <= n; i += 2) {
if (n % i == 0)
return false;
}
return true;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
for (int i = 0; i < a; i++) {
int b = sc.nextInt();
for (int j = b; j >= 1; j--) {
boolean aa = isPrime(j);
if (aa == true && b % j == 0) {
b = j;
break;
}
}
System.out.println(b);
}
}
}
What changes can I make to the program to make it execute faster? What would be a better algorithm for this problem?
The problem with your approach is that for every number N, you try each number smaller or equal to N whether it is a prime and after that whether it is a divisor of N.
Obvious improvement is to check whether it is a divisor first and only then whether it is a prime. But most probably this will not help that much.
What you can do instead is just to start checking each number whether it is a divisor of a number. If it is a divisor, divide it. You continue this till sqrt(N).
I have not done anything with java in a long time, but here is Go implementation, which most probably any Java person will be able to transform to Java.
func biggestPrime(n uint64) uint64 {
p, i := uint64(1), uint64(0)
for i = 2; i < uint64(math.Sqrt(float64(n))) + uint64(1); i++ {
for n % i == 0 {
n /= i
p = i
}
}
if n > 1 {
p = n
}
return p
}
Using my algorithm it will take you O(sqrt(N)) to find the biggest prime of a number. In your case it was O(N * sqrt(N))
Attempt to factor the number into 2 factors. Repeat on the largest factor found so far until you find one that can't be factored -- that is the largest prime factor.
There are many different ways you might try to factor the numbers, but since they are only ints, then Fermat's method or even trial division (going down from sqrt(N)) will probably do. See http://mathworld.wolfram.com/FermatsFactorizationMethod.html

Nested "FOR-loops" not working

I am doing an excercise in the book "Java how to program". The excercise wants me to write a method that determines if a number is "prime". (A "Prime number" is a positiv integer which is only dividable with itself and 1). Then I am supposed to implement the method in an application that displays all integers up to 10 000.
I use "double-values" to test whether the remainder is 0 or not, to test dividability.
Anyway, I just don´t get the program to work, it displays all numbers fro 3, with an increement on how many times each number is displayed (3 44 555 etc). Can anyone please tell me what I´m doing wrong?
The code is the following:
public class Oppgave625
{
public static void main(String[] args)
{
for(double a = 2; a <= 10000; a++)
{
for(double b = 1; b < a; b++)
{
if (prime(a, b) !=0)
{
System.out.printf("%.0f ", prime(a, b));
}
}
}
}
static double prime(double x, double y)
{
if (x % y != 0)
{
return x;
}
else
{
return 0;
}
}
}
Use int instead. double is not good for this purpose
you might want to read this article to understand the use of the % Operator for floating point numbers.
Actually, there were many individual errors in here. I shortened the prime() function to the point where it was only a modulo op, so I was able to inline it. Second, I inverted the test so it checked for numbers that do not have a remainder, and continues to the next number as soon as it finds a divisor. Third, I changed b = 1 so that we do not check for numbers divisible by 1, because this would result to all numbers. Finally, I only print out the numbers for which we do not discover a divisor. The final result:
public static void main(String[] args) {
outer:
for (int a = 2; a <= 1000; a++) {
for (int b = 2; b < a; b++) {
if (a % b == 0) {
continue outer;
}
}
System.out.println(a);
}
}
Edit: I forgot to mention, I also changed the types from floats to ints, since I'm sure that's what you meant.
It's great that you posted sample code for this, but there are several things that are wrong:
you should not use a floating point type for this, but an int or a long. Floating point types should never be used for precise values.
you are making two calls to your prime function, effectively doubling the required steps
your prime function only tells you whether two numbers divide themselves evenly, it does not tell you whether one is a prime or not
for prime numbers, you should use a more efficient algorithm instead of calculating the same values over and over for each number. Look up Sieve of Eratosthenes.
You are approaching the problem like this: The number A is NOT prime, whenever i can find a number B that can divide A without a remainder.
Bur right now, you print out A whenever it is not dividable by B.
Instead you could say: whenever A not divisible by B, increase B. When i found a B to divide A, quit the inner loop, print nothing.
When i found no B, print A and quit loop.
Furthermore, you only have to test for divisibility of A until (a/2)-1.
A prime number is a number that is only divisible by one and itself. That is: one number. Your code is comparing two numbers as in the Euclidean algorithm for testing coprime-ness. This is very different than testing if a number is prime.
Your code should look something like this:
for i = 2 to 10,000 {
if( isPrime(i) ){
print i
}
}
function isPrime( int n ){
for i = 2 to n {
next if i == n
if( n % i == 0 ){
return 0;
}
}
return 1;
}
boolean isPrime = true;
for (int i = 2; i<=100; i++){
for(int j = 2; j<=i/2; j++){
isPrime = true;
if (i%j==0){
isPrime = false;
break;
}
}
if (isPrime){
Log.d("PrimeNumber",""+i);
}
}

Categories