Need help to find bug in factoring code - java

I am coding a program to factor a number into is prime factors. The program works as follows:
1) Input a number that you wish to factor (I will refer to is as "inputNumber")
2) Test to see if you can divide inputNumber by 2,3,5 and 7 (first 4 prime numbers). if you can divide by any of these, then do so as many times as you can (i.e. 12 can be divided by 2 twice, after this, there is a remainder of 3)
note every time I divide by a number, I store that number in an array list and I keep the remainder for further testing
3) Starting with i=11 (the next prime number) in a while loop, I do the following:
while (i < remainder+1) {
divides by i? yes: store i,
repeat until you cant divide by i. i=i+2,
divides by i? yes: store i, repeat until you can't divide by i.
i=i+4, same as before... i=i+2...
and finally stop the loop at i=i+2
}
this way, every successful iteration of the while loop will divide the remainder by numbers finishing by 1,3,7,9. We do not need to test even numbers since we divided by 2 already, nor do we need to test the ones ending by 5 since we already divided by 5. In the end, we
This is a very neat algorithm since it its much much faster than factoring a number by testing one number after the other, in fact, you only need to test 40% of all numbers.
My question is: When I tried factoring 84738329279, a number picked randomly, it omits to put the last prime factor in the list, I can't quite figure this out. the only factors that show up are 41, 61 and 61. Can someone help me find what I'm doing wrong? here is my code:
import java.util.Scanner;
import java.math.BigInteger;
public class Test {
public static void main(String[] args) {
// create a scanner object for inputs
Scanner in = new Scanner(System.in);
// prompt user for number to factor
System.out.print("enter a number to factor: ");
String digits = in.next();
BigInteger BigDigits = new BigInteger(digits);
BigInteger[] results = factor.factorThis(BigDigits);
System.out.print("Factors are ");
for (int i=0; i<results.length;i++){
System.out.print(results[i] + " ");
}
System.out.println("");
}
}
import java.util.ArrayList;
import java.math.BigInteger;
public class factor {
// Returns the prime factors of the BigInteger number
public static BigInteger[] factorThis(BigInteger number) {
BigInteger i = new BigInteger("11");
ArrayList<BigInteger> divisors = new ArrayList<BigInteger>(0);
BigInteger[] firstPrimes = new BigInteger[4];
firstPrimes[0] = new BigInteger("2");
firstPrimes[1] = new BigInteger("3");
firstPrimes[2] = new BigInteger("5");
firstPrimes[3] = new BigInteger("7");
// loop that test for first 4 prime numbers
for (int l=0;l<4;l++){
while ((number.mod(firstPrimes[l])).compareTo(BigInteger.ZERO) == 0) {
number = number.divide(firstPrimes[l]);
divisors.add(firstPrimes[l]);
}
}
// loop that factors only numbers finishing by 1,3,7,9
while (i.compareTo(number) == -1){
// check for ending by 1
if ((number.mod(i)).compareTo(BigInteger.ZERO) == 0) {
while (number.mod(i).compareTo(BigInteger.ZERO) == 0){
number = number.divide(i);
divisors.add(i);
}
}
else if ((number.mod(i)).compareTo(BigInteger.ZERO) != 0){
i=i.add(firstPrimes[0]);
}
// check for ending by 3
if ((number.mod(i)).compareTo(BigInteger.ZERO) == 0) {
while (number.mod(i).compareTo(BigInteger.ZERO) == 0){
number = number.divide(i);
divisors.add(i);
}
}
else if ((number.mod(i)).compareTo(BigInteger.ZERO) != 0){
i=i.add(firstPrimes[0].multiply(firstPrimes[0]));
}
//check for ending by 7
if ((number.mod(i)).compareTo(BigInteger.ZERO) == 0) {
while (number.mod(i).compareTo(BigInteger.ZERO) == 0){
number = number.divide(i);
divisors.add(i);
}
}
else if ((number.mod(i)).compareTo(BigInteger.ZERO) != 0){
i=i.add(firstPrimes[0]);
}
// check for ending by 9
if ((number.mod(i)).compareTo(BigInteger.ZERO) == 0) {
while (number.mod(i).compareTo(BigInteger.ZERO) == 0){
number = number.divide(i);
divisors.add(i);
}
}
else if ((number.mod(i)).compareTo(BigInteger.ZERO) != 0){
i=i.add(firstPrimes[0]);
}
}
// store prime factors into a BigInt array
String[] strArrayDivisors = divisors.toString().replaceAll("\\[", "").replaceAll("\\]","").replaceAll("\\s","").split(",");
BigInteger[] BigIntDivisors = new BigInteger[strArrayDivisors.length];
for(int j=0;j<strArrayDivisors.length;j++){
BigIntDivisors[j] = new BigInteger(strArrayDivisors[j]);
}
// returns all factors of "number"
return BigIntDivisors;
}
}
Thanks in advance.

First, 84738329279 = 41 * 61 * 61 * 555439. Your 41, 61, and 61 are correct.
But when your algorithm terminates, you are left with the last prime number still in number. You'll need to add code that tests number at the end: if it's 1, then you're already finished, else it needs to add it to divisors so it gets printed later.

Related

Basic Java - Finding if a number is a prime number using while loop

I have a question regarding an answer that was given here a while ago.
I came up with the same answer myself in the code attached but I'm trying to understand why do I need to divide the input number by 2 (line 10), and not just let the loop run its course till the value of the input number achieved.
1 import java.util.Scanner;
2 public class numIsPrime {
3 public static void main(String[] args) {
4 Scanner sc = new Scanner(System.in);
5 int i = 2;
6 boolean isPrime = true;
7 System.out.println("Enter a number");
8 int num = sc.nextInt();
9
10 while (i < num ) // (i <= num / 2)
11 {
12 if (num % i == 0)
13 isPrime = false;
14 i++;
15 }
16
17 if (isPrime)
18 System.out.println(num + " is a prime number");
19 else // !isPrime
20 System.out.println(num + " isn't a prime number");
21
22 }
23 }
This is the simplest way to calculate if an integer n is probably a prime:
public static boolean isPrime (int n) {
if (n < 2) return false;
BigInteger bigInt = BigInteger.valueOf(n);
return bigInt.isProbablePrime(100);
}
You can insert this function call in a loop where you can pass a new number every iteration. I am using the implementation of BigInteger provided by Java to do the calculation, rather than writing my own. UNLESS this is a homework and you are required to write your own algorithm, I would use this solution.
This base method can then be used for calculating other types of prime numbers. A complete answer can be found here.
UPDATE:
The int parameter in BigInteger.isProbablePrime(int) is a measure of the uncertainty that the caller is willing to tolerate. The larger the number, the "slower" it executes (but the more certain it is). Also, going back to the original question (already answered in the OP's comments section):
why do I need to divide the input number by 2 (line 10), and not just
let the loop run its course till the value of the input number
achieved.
This is an optimization that will make your evaluation run twice as fast. For example, suppose an evaluation of n integers take 10 minutes to complete, excluding even numbers should take half the time. That's a significant improvement. Although you should not optimize prematurely, these sort of optimizations should be done right from the get go. Basically, we all know that even numbers are not prime, so why evaluate it? You want to evaluate unknowns. In my solution, I only evaluate values greater than 2 because by definition, values less or equal to 2 are not prime. I am merely solving that by definition or by mathematical properties.
As mentioned in the comments, dividing by 2 is a simplest optimization to reduce the number of checks, however, existing code has a few issues (e.g. returning true for 0 and 1 which are NOT prime numbers) and may be further optimized:
break/end the loop as soon as isPrime is set to false
skip even numbers by incrementing by 2
calculate until i * i <= num
If this limit is reached, it means that no factor i of num has been found in the range [2, num/i], therefore by definition of the prime numbers, all the remaining numbers in the range [num/i, num] are neither the factors of num, and therefore num is prime.
Scanner sc = new Scanner(System.in);
System.out.println("Enter a number");
int num = sc.nextInt();
boolean isPrime = num > 1 && (num % 2 != 0 || num == 2);
int i = 3;
while (isPrime && i * i <= num) {
if (num % i == 0)
isPrime = false;
i += 2; // skip even numbers
}
if (isPrime)
System.out.println(num + " is a prime number");
else
System.out.println(num + " isn't a prime number");
More optimizations are possible if the divisibles of 3 (except 3) are excluded similar to the exclusion of even numbers, then the search continues from 5 and the candidates for primality comply with 6n ± 1 rule (e.g., 5 = 6 - 1, 7 = 6 + 1, 11 = 12 - 1, 13 = 12 + 1, etc.):
boolean isPrime = num > 1 && (num % 2 != 0 || num == 2) && (num % 3 != 0 || num == 3);
int i = 5;
int d = 2;
while (isPrime && i * i <= num) {
if (num % i == 0)
isPrime = false;
i += d; // check only non-even numbers
d = 6 - d; // switch 2 to 4 and back to 2
}

Check whether a number is a sum of two prime numbers

The problem is to check a random number n can be the sum of 2 random prime numbers. For example,
if n=34 the possibilities can be (3+31), (5+29), (17+17)...
So far I have managed to save prime numbers to the array, but have no clue how I could check, if n is the sum of 2 prime numbers.
This is part of my code:
public static void primeNumbers(int n) {
int i = 0, candidate = 2, countArray = 0, countPrime = 0;
boolean flag = true;
while (candidate <= n) {
flag = true;
for (i = 2; i < candidate; i++) {
if ((candidate % i) == 0) {
flag = false;
break;
}
}
if (flag) {
countPrime++;
}
candidate++;
}
int[] primeNumbers = new int[countPrime];
while (candidate <= n) {
flag = true;
for (i = 2; i < candidate; i++) {
if ((candidate % i) == 0) {
flag = false;
break;
}
}
if (flag) {
primeNumbers[countArray] = candidate;
}
candidate++;
countArray++;
}
for (i = 0; i <= primeNumbers.length; i++) {
}
}
First I counted how many prime numbers are between 1-n so I can declare and initialize my array for prime numbers. Then I save prime numbers to the array. But now I have no idea how I could check if n is the sum of 2 prime numbers.
Given that you already have list of "prime numbers less than the given number", It is a very easy task to check if two prime numbers can sum to given number.
for(int i=0; i<array.length; i++){
int firstNum = array[i];
int secondNum = givenNum - firstNum;
/* Now if it is possible to sum up two prime nums to result into given num, secondNum should also be prime and be inside array */
if(ArrayUtils.contains(array, secondNum)){
System.out.println("Yes, it is possible. Numbers are "+ firstNum + " and " + secondNum);
}
}
EDIT: ArrayUtils is part of Apache Commons Lang library
You can however use ArrayList instead to use contains method.
You do not have to check all prime numbers from 1 to the given number or you don't even need an array.
Algorithm one can be;
First of all write a function that checks whether a given number is prime.
Split the number into two parts, 0 and the remaining value(the number itself). Now start decreasing the number part by 1 and start adding 1 to 0 simultaneously. Stop when the number part which we are decreasing becomes 0 or both the parts are prime numbers.
Another algorithm can be like this;(It is similar to the accepted answer)
Start subtracting prime numbers from the given number starting from 2.Check whether the subtraction is also prime.
The time you get the subtraction as a prime number, stop , you have got the two prime numbers that sum up to the given number.

How to determine if a number is prime

Okay my issue is less of how to figure out if a number is prime, because I think I figured that out, but more of how to get it to display properly.
Here's my code:
public static void main(String[] args) {
// Declare Variables
int randomNumbers = 0;
int sum = 0;
//Loop for number generation and print out numbers
System.out.print("The five random numbers are: ");
for (int i = 0; i <= 4; i++)
{
randomNumbers = (int)(Math.random()*20);
sum += randomNumbers;
if (i == 4) {
System.out.println("and " + randomNumbers + ".");
}
else {
System.out.print(randomNumbers + ", ");
}
}
//Display Sum
System.out.println("\nThe sum of these five numbers is " + sum + ".\n");
//Determine if the sum is prime and display results
for(int p = 2; p < sum; p++) {
if(sum % p == 0)
System.out.println("The sum is not a prime number.");
else
System.out.println("The sum is a prime number.");
break;
}
}
}
Now my problem is, if the number ends up being something like 9, it'll say it is a prime number, which it is not. I think the issue is that the break is stopping it after one loop so it's not incrementing variable p so it's only testing dividing by 2 (I think). But if I remove the break point it will print out "The sum is/is not a prime number" on every pass until it exits the loop. Not sure what to do here.
Your method for finding if your number is prime is the correct method.
To make it so that it does not consistently print out whether or not the number is prime, you could have an external variable, which represents whether or not the number is prime.
Such as
boolean prime = true;
for (int p = 2; p < sum; p++) {
if (sum % p == 0) {
prime = false;
break;
}
}
if (prime)
System.out.println("The sum is a prime number.");
else
System.out.println("The sum is not a prime number.");
By doing this method the program will assume the number is prime until it proves that wrong. So when it finds it is not prime it sets the variable to false and breaks out of the loop.
Then after the loop finishes you just have to print whether or not the number was prime.
A way that you could make this loop faster is to go from when p = 2 to when p = the square root of sum. So using this method your for loop will look like this:
double sq = Math.sqrt((double)sum);
for (int p = 2; p < sq; p++) {
//Rest of code goes here
}
Hope this helps
You need to store whether or not the number is prime in a boolean outside of the loop:
//Determine if the sum is prime and display results
boolean isPrime = true;
for(int p = 2; p < sum; p++) {
if(sum % p == 0){
isPrime = false;
break;
}
}
if(isPrime){
System.out.println("The sum is a prime number.");
} else {
System.out.println("The sum is not a prime number.");
}
You are right, currently your code tests dividing by two, and the break command is stopping after one loop.
After the first go of your loop (p==2), the break will always stop the loop.
The fastest fix to your code will change the loop part like this:
boolean isPrime=true;
for(int p = 2; p < sum; p++) {
if(sum % p == 0) {
isPrime=false;
System.out.println("The sum is not a prime number.");
break;
}
}
if (isPrime)
System.out.println("The sum is a prime number.");
This code can be improved for efficiency and for code elegance.
For efficiency, you don't need to check divisibility by all numbers smaller than sum, it's enough to check all numbers smaller by square-root of sum.
For better code, create a seperate function to test if a number is prime.
Here is an example that implements both.
// tests if n is prime
public static boolean isPrime(int n) {
if (n<2) return false;
for(int p = 2; p < Math.sqrt(n); p++) {
if(n % p == 0) return false; // enough to find one devisor to show n is not a prime
}
return true; // no factors smaller than sqrt(n) were found
}
public static void main(String []args){
...
System.out.println("sum is "+ sum);
if (isPrime(sum))
System.out.println("The sum is a prime number.");
else
System.out.println("The sum is not a prime number.");
}
Small prime numbers
Use Apache Commons Math primality test, method is related to prime numbers in the range of int. You can find source code on GitHub.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
// org.apache.commons.math3.primes.Primes
Primes.isPrime(2147483629);
It uses the Miller-Rabin probabilistic test in such a way that a
result is guaranteed: it uses the firsts prime numbers as successive
base (see Handbook of applied cryptography by Menezes, table 4.1 / page 140).
Big prime numbers
If you are looking for primes larger than Integer.MAX_VALUE:
Use BigInteger#isProbablePrime(int certainty) to pre-verify the prime candidate
Returns true if this BigInteger is probably prime, false if it's
definitely composite. If certainty is ≤ 0, true is returned.
Parameters: certainty - a measure of the uncertainty that the caller
is willing to tolerate: if the call returns true the probability that
this BigInteger is prime exceeds (1 - 1/2certainty). The execution
time of this method is proportional to the value of this parameter.
Next use "AKS Primality Test" to check whether the candidate is indeed prime.
So many answers have been posted so far which are correct but none of them is optimized. That's why I thought to share the optimized code to determine prime number here with you. Please have a look at below code snippet...
private static boolean isPrime(int iNum) {
boolean bResult = true;
if (iNum <= 1 || iNum != 2 && iNum % 2 == 0) {
bResult = false;
} else {
int iSqrt = (int) Math.sqrt(iNum);
for (int i = 3; i < iSqrt; i += 2) {
if (iNum % i == 0) {
bResult = false;
break;
}
}
}
return bResult;
}
Benefits of above code-:
It'll work for negative numbers and 0 & 1 as well.
It'll run the for loop only for odd numbers.
It'll increment the for loop variable by 2 rather than 1.
It'll iterate the for loop only upto square root of number rather than upto number.
Explanation-:
I have mentioned the four points above which I'll explain one by one. Code must be appropriately written for the invalid inputs rather the only for valid input. Whatever answers have been written so far are restricted to valid range of input in which number iNum >=2.
We should be aware that only odd numbers can be prime, Note-: 2 is the only one even prime. So we must not run for loop for even numbers.
We must not run for loop for even values of it's variable i as we know that only even numbers can be devided by even number. I have already mentioned in the above point that only odd numbers can be prime except 2 as even. So no need to run code inside for loop for even values of variable i in for.
We should iterate for loop only upto square root of number rather than upto number. Few of the answers has implemented this point but still I thought to mention it here.
With most efficient time Complexity ie O(sqrt(n)) :
public static boolean isPrime(int num) {
for (int i = 2; i * i <= num; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
you can use the Java BigInteger class' isProbablePrime method to determine and print whether the sum is prime or not prime in an easy way.
BigInteger number = new BigInteger(sum);
if(number.isProbablePrime(1)){
System.out.println("prime");
}
else{
System.out.println("not prime");
}
You can read more about this method here https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html#isProbablePrime%28int%29

Difference of implementation and mathematical proof of efficient algorithm for finding prime numbers

When i study from Introduction to Java programming book of Liang, i am stuck at a point. The problem is to find prime numbers efficiently.
In order to find whether n is prime or not, we must check whether n is divisible by numbers 2,3,4,...,sqrt(n) .
We can make this algorithm more efficient by checking whether n is divisible by numbers 2,3,4,...,floor(sqrt(n)).
For example, numbers between 36 and 48, their (int)(Math.sqrt(number)) is 6. But, according to the below program, for number=40, squareRoot is 7, not 6. Namely, according to the mathematical proof, we check whether 40 is prime by checking 40 is divisible by 2,3,4,5,6.
According to the below program, we check whether 40 is prime by checking 40 is divisible by 2,3,4,5,6,7. This the contradiction. I don't understand it. Help please.
Here is the algorithm implementing this problem :
import java.util.Scanner;
public class EfficientPrimeNumbers {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Find all prime numbers <= n, enter n: ");
int n = input.nextInt();
// A list to hold prime numbers
java.util.List<Integer> list =
new java.util.ArrayList<Integer>();
final int NUMBER_PER_LINE = 10; // Display 10 per line
int count = 0; // Count the number of prime numbers
int number = 2; // A number to be tested for primeness
int squareRoot = 1; // Check whether number <= squareRoot
System.out.println("The prime numbers are \n");
// Repeatedly find prime numbers
while (number <= n) {
// Assume the number is prime
boolean isPrime = true; // Is the current number prime?
if (squareRoot * squareRoot < number) squareRoot++;
// For numbers between 36 and 48, squareRoot is 7 which contradicts with the matematical proof.!!!
// ClosestPair if number is prime
for (int k = 0; k < list.size()
&& list.get(k) <= squareRoot; k++) {
if (number % list.get(k) == 0) { // If true, not prime
isPrime = false; // Set isPrime to false
break; // Exit the for loop
}
}
// Print the prime number and increase the count
if (isPrime) {
count++; // Increase the count
list.add(number); // Add a new prime to the list
if (count % NUMBER_PER_LINE == 0) {
// Print the number and advance to the new line
System.out.println(number);
}
else
System.out.print(number + " ");
}
// Check if the next number is prime
number++;
}
System.out.println("\n" + count +
" prime(s) less than or equal to " + n);
}
}
The program only checks for divisibility by primes lower than or equal to sqrt(number) + 1. Once a prime number is detected, it gets added to your list object:
if (isPrime) {
count++; // Increase the count
list.add(number); // Add a new prime to the list
Here is where you check for divisibility by numbers in this list:
for (int k = 0; k < list.size() && list.get(k) <= squareRoot; k++) {
if (number % list.get(k) == 0) { // If true, not prime
So for numbers between 36 and 48, it checks 2, 3, 5, 7, which is actually better than 2, 3, 4, 5, 6. Asymptotically, they're still the same, but in practice, you save some work by only checking for divisibility against the primes.
In fact you can save an operation and change the <= in list.get(k) <= squareRoot to <, for the reasons you describe. Then it won't even bother with 7 for numbers between 36 and 48, and it will be closer to the theory you have.

Showing NINE as a prime number while executing this code.Help me

//Getting Prime numbers from 2 to given range.
//When Inner for loop is running for number 2, it is printing 9 as a prime number.
import java.util.*;
import java.io.*;
class A
{
public static void main(String args[])
{
System.out.println("Enter the number till which the prime number is to be printed:");
Scanner sc = new Scanner(System.in);
int limit = sc.nextInt();
System.out.println("Printing the prime numbers from 1 to "+limit);
for(int num =2; num<=limit; num++)
{
for(int d=2; d<=num; d++)
{
if(num%d == 0)
{
break;
}
if()
{
System.out.println(num);
break;
}
}
}
}
}
Above the second loop keep a flag as true which means initially the number is a prime number.
boolean flag = true;
Second loop condition shall be d <= num/2
Inside the second loop to break if its not prime, or divisible by a number.
if(num%d == 0)
{
flag = false;
break;
}
Outside the second loop, print it if the flag is still true:
if(flag){
System.out.println(num);
}
Remember: For large scale prime number checking or generation, the algorithm of Sieve is always best.
I have a bad news. This program finds not the prime number but the odd numbers: 3, 5, 7, 9 etc.
You are printing the values if it is not divisible.
all the non prime numbers from 2 to 8 are divisible by 2 and hence it is showing only prime numbers.
in case when number is 9, it is printing 9 because 9%2 is not 0.

Categories