I currently have a program to find the prime factorisation of a given number; works fine with smaller numbers, but it takes ages for anything over a million. My code is extremely inefficient, finding all prime numbers below the input and checking which ones divide without a remainder. I don't know how to make it less inefficient, any help?
static ArrayList<Integer> primeNumbersBelow(long n) {
ArrayList<Integer> ay = new ArrayList<Integer>();
ay.add(2);
for(int i = 3; i < ((n % 2 != 0) ? (n + 1) / 2 : n / 2); i++) {
boolean divides = false;
for(int j = 2; j < i; j++) {
if(i % j == 0) {
divides = true;
}
}
if(!divides) {
ay.add(i);
System.out.println(i);
}
}
return ay;
}
static ArrayList<Integer> primeFactorisationOf() {
ArrayList<Integer> ay = new ArrayList<Integer>();
ArrayList<Integer> aay = primeNumbersBelow(input);
long n = input;
for(int i = 0, len = aay.size(); i < len; i++) {
int f = aay.get(i);
boolean run = true;
while(run) {
if(n % f == 0) {
ay.add(f);
n /= f;
} else {
run = false;
}
}
}
return ay;
}
From Mr Lars Vogel # vogella...
public static List<Integer> primeFactors(int number) {
int n = number;
List<Integer> factors = new ArrayList<Integer>();
for (int i = 2; i <= n; i++) {
while (n % i == 0) {
factors.add(i);
n /= i;
}
}
return factors;
}
Sticking to your general algorithm and not re-writing your primesBelow(..) method: I would say:
Once divides = true, you can break out of the for-loop
The complex for loop termination condition for primality check can be reduced to the Math.sqrt(n) - I won't go through the math, but you can look that up yourself.
One way to improve the code is to remove the IO inside your loop structure.
That is,
static ArrayList<Integer> primeNumbersBelow(long n) {
ArrayList<Integer> ay = new ArrayList<Integer>();
ay.add(2);
for(int i = 3; i < ((n % 2 != 0) ? (n + 1) / 2 : n / 2); i++) {
boolean divides = false;
for(int j = 2; j < i; j++) {
if(i % j == 0) {
divides = true;
}
}
if(!divides) {
ay.add(i);
//REMOVE THE FOLLOWING LINE
System.out.println(i);
}
}
return ay;
}
I'm sure you'll see a huge performance boost just from that alone.
Related
I wanted to use a for and a while loop to obtain the prime factors of a number. My while loop example works fine which I have posted below my for loop example. However, my for loop does not work, and i am guessing that I can't use a continue in the same manner that I used it in the while loop. If this is true, then how would I accomplish this. I have not been able to find a basic beginners example of this using a for loop. Thanks
// My getting largest prime factor using a for loop
public class LargestPrime{
public static void main(String[] args) {
int number = 36;
int largestPrime = 0;
for ( int i = 2; i <= number; i++){
if (number % i == 0){
largestPrime = i;
number /= i;
continue;
}
System.out.println(" largest prime = " + i);
}
}
}
//*******************************************************************
//*******************************************************************
public class LargestPrime {
// gettting largest prime using a while loop
public static int getLargestPrime(int number) {
if (number <= 1) {
return -1;
}
int largestPrime = 0;
int count = 2;
while (count <= number) {
if (number % count == 0) {
largestPrime = count;
number = number / count;
continue;
}
count++;
}
return largestPrime;
}
}
The problem is that continue in a for loop executes the update part (i++), which your while loop didn't.
The other problem is that you're printing inside the loop.
There are multiple way to fix this:
Do i-- before continue, so it evens out to nothing with the i++. This is a fairly common way to handle this.
Since you don't have any code after the if statement, you don't need the continue.
for (int i = 2; i <= number; i++) {
if (number % i == 0) {
largestPrime = i;
number /= i;
i--; // to retry same `i` value
}
}
Do the i++ "yourself", i.e. not as part of for loop:
for (int i = 2; i <= number; ) {
if (number % i == 0) {
largestPrime = i;
number /= i;
continue;
}
i++;
}
Or:
for (int i = 2; i <= number; ) {
if (number % i == 0) {
largestPrime = i;
number /= i;
} else {
i++;
}
}
Use a while loop inside the for loop:
for (int i = 2; i <= number; i++) {
while (number % i == 0) {
largestPrime = i;
number /= i;
}
}
That can be shortened to:
for (int i = 2; i <= number; i++)
for (; number % i == 0; number /= i)
largestPrime = i;
Though rather than assign largestPrime repeatedly, you could do this:
for (int i = 2; i <= number; i++) {
if (number % i == 0) {
largestPrime = i;
do {
number /= i;
} while (number % i == 0);
}
}
I wrote some code to find prime numbers up to a given number. Could you guys let me know ways to make my code more efficient or better? Or give insight on how I did? In addition, there is a problem in my code where certain numbers repeats twice or three times in a pattern. How do I fix this?
public class PrimeNumber2 {
public static void main(String[] args)
{
int max_prime = 10000;
for(int i = 3; i < max_prime; i+=2)
{
for(int j = 1; j < Math.sqrt(i); j++)
{
if(i % j == 0)
{
System.out.println(i);
}
}
}
}
}
Have a look at:
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
This is quite a nice way of doing it.
Here is some code for you to look at:
public void runEratosthenesSieve(int upperBound) {
int upperBoundSquareRoot = (int) Math.sqrt(upperBound);
boolean[] isComposite = new boolean[upperBound + 1];
for (int m = 2; m <= upperBoundSquareRoot; m++) {
if (!isComposite[m]) {
System.out.print(m + " ");
for (int k = m * m; k <= upperBound; k += m)
isComposite[k] = true;
}
}
for (int m = upperBoundSquareRoot; m <= upperBound; m++) {
if (!isComposite[m]) {
System.out.print(m + " ");
}
}
Here´s a tuned version of yours.
I did put the check if the number is prime into a seperate method. That´s also a part of the reason why your version did print values multiple times, since if it found out that it has a divisor, then it would print the values. (Also you´r algorythm would print basicly everything despite it beeing prime or not, for example it prints 15 and 27).
The reason why it did print multiple values was, that once you found a divisor it would have printed i, but it would continue looping. If it would have found another divisor, it would print i again(you can notice that it does not only print prime numbers).
Here is the fixed version of your´s
public static void main(String[] args) {
if(isPrime(2)) {
System.out.println(2);
}
int max_prime = 10000;
for(int i = 3; i < max_prime; i+=2)
{
if(isPrime(i)) {
System.out.println(i);
}
}
}
private static boolean isPrime(int n) {
if(n<=1) return false;
if(n == 2) return true;
for(int i = 2;i*i<=n;++i) {
if(n%i == 0) return false;
}
return true;
}
Try this.
public class PrimeNumber2 {
public static void main(String[] args)
{
int max_prime = 10000;
System.out.println(2);
L: for (int i = 3; i < max_prime; i += 2)
{
for (int j = 3, max = (int)Math.sqrt(i); j <= max ; j += 2)
{
if(i % j == 0)
{
continue L;
}
}
System.out.println(i);
}
}
}
Here a way using parallelStream
System.out.println(2);
IntStream.range(1, 10000000)
.map(i -> i * 2 + 1)
.filter(i -> (i & 1) != 0 && IntStream.range(1, (int) (Math.sqrt(i)-1)/2)
.map(j -> j * 2 + 1)
.noneMatching(j -> i % j == 0)
.forEach(System.out::println);
Note: the ranges test the n-th odd number.
public static void main(String[] args) {
int upperBound = 30;
List<Integer> primes = new ArrayList<>();
// loop through the numbers one by one
for (int number = 2; number < upperBound; number++) {
boolean isPrimeNumber = true;
// check to see if the number is prime
for (int j = 2; j < number; j++) {
if (number % j == 0) {
isPrimeNumber = false;
break; // exit the inner for loop
}
}
// print the number if prime
if (isPrimeNumber) {
primes.add(number);
}
}
System.out.println("The number of prime is: " + primes.size() + ", and they are: " + primes.toString());
}
possible to dupplicate
get prime numbers and total prime numbers in range
public boolean isPrimeNumber(int number) {
for (int i=2; i<=number/2; i++) {
if (number % i == 0) {
return false;
}
}
return true;
}
public class assignment6part3 {
public static void main(String[] args) {
int q = 0;
for ( int count=1; count <= 10000; count++) {
if (Prime(count)) {
q = q + 1;
}
}
System.out.println("It comes out " + q + " times.");
}
public static boolean Prime(int n) {
if (n <= 1) {
return false;
}
for (int i = 1; i < Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
}
I'm trying to get the number of prime numbers between 0 and 10000, but when I run this, it says there are 0 prime numbers. What part of the code is causing this error?
Inside your function Prime your for loop runs like ::
for(int i = 1; i < Math.sqrt(n); i++), starting from i = 1 and every number is divisible by 1 and hence 0 prime numbers.. :P
Initialization condition for i shall be i = 2
Other things you might consider changing ::
for (int i = 1; i < Math.sqrt(n); i++) shall be changed to
for (int i = 1; i <= Math.sqrt(n); i++)
NOTE :: A more optimal way to find Primes would be https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
The code is returning false before it actually checks the numbers, because every number is divisible by 1. Also, in some cases such as 25 and 49, the factors are not less than the square root. Try this:
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
return false;
}
}
This is my code for finding the sum of primes.It works good with some low numbers but if it's 2000000(2 million) it never ends.Anybody can help me?
import java.math.BigInteger;
public class Problem010{
public static void main(String[] args) {
BigInteger sum = new BigInteger("2");
//for (int i=3; i<2000000; i++) {
for(int i=3; i<10; i++){
for (int j=2; j<i; j++){
if (i % j == 0)
break;
else if (i == j+1){
sum = sum.add(BigInteger.valueOf(i));
}
}
}
System.out.println("Sum = "+sum);
}
}
your answer is 142913828922 but how?
I just changed your algorithm a little bit:
public static void main(String[] args) {
BigInteger sum = new BigInteger("2");
boolean isPrime = true;
for (int i=3; i<2000000; i++) {
double aa = Math.sqrt((double)i);
for (int j=2; j<=aa; j++){
if (i % j == 0){
isPrime = false;
break;
}
}
if(isPrime){
sum = sum.add(BigInteger.valueOf(i));
}
isPrime = true;
}
System.out.println("Sum = "+sum);
}
instead of going through all the numbers from 2 to i I just go from 2 to sqrt(i) and this improve your code running time a lot :)
#Lrrr, answer is correct. But algorithm can be further optimised. Look at my isPrime algorithm. For 2 million you don't need the BigInteger.
long sum = 2;// new BigInteger("2");
for (int i=3; i<2000000; i++) {
if(isPrime(i)) {
sum = sum + i;//.add(BigInteger.valueOf(i));
}
}
System.out.println("Sum = "+sum);
Here is isPrime method.
static boolean isPrime(int n) {
if (n < 2) {
return false;
}
if (n == 2 || n == 3) {
return true;
}
if ((n & 1) == 0 || n % 3 == 0) {
return false;
}
int sqrtN = (int) Math.sqrt(n) + 1;
for (int i = 6; i <= sqrtN; i += 6) {// loop 6 step
if (n % (i - 1) == 0 || n % (i + 1) == 0) {
return false;
}
}
return true;
}
An efficient solution could be to use Sieve of Eratosthenes to find out which number is prime below 2,000,000 (or any other number), and than post-process and sum them all:
int n = 2000000;
boolean[] isPrime = new boolean[n];
//preprocess - set up the array
for (int i = 2; i<n;i++) isPrime[i] = true;
//run sieve:
for (int i = 2; i < (int) Math.sqrt(n) + 1; i++) {
if (isPrime[i]) {
for (int j = 2; j*i < n; j++) isPrime[i*j] = false;
}
}
//sum primes:
long sum = 0;
for (int i = 2; i < n; i++) {
if (isPrime[i]) sum+=i;
}
System.out.println(sum);
As opposed to checking for each number at a time if it is prime or not (which takes O(sqrt(n)) - and by doing it for all numbers you get O(nsqrt(n)), in here you aggregate knowledge from previous iterations, effectively lowering the complexity to O(nloglog(n)), which is significantly faster for large enough values of n.
This comes at a cost of O(n) additional space.
You could use Sieve of Eratosthenes algorithm, it is more efficient then yours.
1) Store all numbers between 2 and N in array and mark them all as prime numbers.
2) Start from X = 2, and mark all its i*X (2X, 3X..), where i is natural number less then or equal N, multipliers as not prime. Do not mark X.
3) Find the next number greater then X which is not marked and repeat the procedure. If there is no such number, stop.
4) Remaining numbers in your array are prime
Something like this:
public static boolean[] findPrimes (int N) {
boolean[] primes = new boolean[N + 1];
// assume that all numbers are prime within given range
for (int i = 2; i <= N; i++) {
primes[i] = true;
}
// for all numbers in range, starting from 2
for (int i = 2; i*i <= N; i++) {
// mark natural multiples of i as nonprime
if (primes[i]) {
for (int j = i; i*j <= N; j++) {
primes[i*j] = false;
}
}
return primes;
}
5) Iterate over returned primes and sum indexes of TRUE values
I developed my own solution and it completes in 700 milliseconds to find all below 2 million.
I use the iterative method but I just stop looking for the numbers greater than (n/i)+1 where n is the number being checked if it is prime and i is the number in the iterative loop to see if it is a divisor.
public void run () {
long sumOfPrimes = 2;
int maxNumber = 2000000;
int counter = 0;
for (int i = 3; i <= maxNumber; i = i+2) {
if(isPrimeOptimized(i)){
sumOfPrimes = sumOfPrimes + i;
counter ++;
}
}
System.out.println("num of primes is " + counter);
System.out.println("sum of primes is " + sumOfPrimes);
}
private boolean isPrimeOptimized(int n){
int limitToDivide = n;
for(int i=2;i<=limitToDivide && i<n;i++){
if(n%i == 0)
return false;
else
limitToDivide = (n/i) + 1;
}
return true;
}
So far no one has actually implemented the Sieve correctly. Double check the wikipedia page and pay attention to how you are looping through the numbers. Without any optimizations using an array of int (or booleans) it should take only a few seconds in Java.
I am new here. I am trying to solve this exercise Problem 18 just for reinforcing my solving skills. I've already coded the answer. The task asks for "How many of the primes below 1,000,000 have the sum of their digits equal to the number of days in a fortnight?" (a fortnight is 14 days). My answers is 16708, but it is wrong. I hope you can help me. I don't know what my error is. I have 2 methods, 1 for generating the primes, and another for counting the digits of each prime.
This is my code:
import java.util.ArrayList;
import java.util.List;
public class Problema18 {
public static void main(String args[]) {
ArrayList<Integer> num = primes();
System.out.println(num);
count(primes());
}
public static ArrayList<Integer> primes() {
List<Integer> primes = new ArrayList<Integer>();
primes.add(2);
for (int i = 3; i <= 1000000; i += 2) {
boolean isPrime = true;
int stoppingPoint = (int) (Math.pow(i, 0.5) + 1);
for (int p : primes) {
if (i % p == 0) {
isPrime = false;
break;
}
if (p > stoppingPoint) { break; }
}
if (isPrime) { primes.add(i); }
}
// System.out.println(primes);
return (ArrayList<Integer>) primes;
//System.out.println(primes.size());
}
public static void count(ArrayList<Integer> num) {
int count = 0;
for (int i = 0; i <= num.size() - 1; i++) {
int number = num.get(i);
String num1 = String.valueOf(number);
int sum = 0;
for (int j = 0; j < num1.length(); j++) {
sum = Integer.parseInt(num1.charAt(j) + "") + sum;
if (sum == 14) { count++; }
}
System.out.println(sum);
}
System.out.println(count);
}
}
You should check whether sum == 14 outside the inner for loop. What happens now is that you also count those primes for which the sum of digits is larger than 14 but the sum of the digits in some prefix of the prime is equal to 14.
This part...
if (sum == 14) {
count++;
}
should be outside the inner for-loop - i.e. you want to do it each time you pass through the i for-loop, but not each time you pass through the j for-loop.
Like this:
public static void count(ArrayList<Integer> num) {
int count = 0;
for (int i = 0; i <= num.size() - 1; i++) {
int number = num.get(i);
String num1 = String.valueOf(number);
int sum = 0;
for (int j = 0; j < num1.length(); j++) {
sum = Integer.parseInt(num1.charAt(j) + "") + sum;
}
System.out.println(sum);
if (sum == 14) {
count++;
}
}
System.out.println(count);
}