Efficient Prime Number Computing Program Java - java

So I was trying to make a prime number calculator in java that goes from 1 up to the upper limit of the range given by the user and prints out all of the primes.
One way of approaching this was by simply using a nested for loop and testing divisibility for every number in the range by all of the numbers less than it.
However, I figured it would be more efficient to only test prime numbers to avoid repeated factors and speed up the program.
For example, if the number we were on was 16, rather than testing if it's divisible by 2,3,4,5,...14,15,16, I could only test out 2,3,5,7,11,13 and stop once a factor is found.
So I tried to make an array to store all of the primes found so far and only use those values to test for the next number.
Here's my code, I can't figure out why it's not working
Scanner sc = new Scanner (System.in);
System.out.print ("Enter the upper limit: ");
int high = sc.nextInt();
boolean isPrime = true;
int[] primearray = new int[0];
for (int num = 1; num <= high; num++)
{
for (int x: primearray)
{
if (num%x==0)
{
isPrime = false;
break;
}
}
if (isPrime == true) {
int size = primearray.length;
primearray = new int[size+1];
primearray [size] = num;
System.out.println (num);
}
}

First of all, 1 isn't prime. By starting your outer loop at 1, your prime array ends up with 1 in it and everything else will then test as not prime. Start your outer loop at int num = 2.
Second, you aren't copying over the existing known primes when you expand primearray. You can use
primearray = Arrays.copyOf(primearray, size+1);
which will make a new array with all the old contents copied and space for one more value.
Finally, you might want to check out the Sieve of Eratosthenes. A careful implementation of that algorithm will be more efficient than your current algorithm, which requires an expensive array reallocation every time you find a prime. You can use a BitSet to keep track of the flags that the sieve needs.

You have wrong in logic
boolean isPrime = true;
this variable should be declared in for loop, let 's imagine, if you find out 4 is not prime then isPrime = false, then you check 5 but there is not any code block that set isPrime = true.
And this block:
if (isPrime == true) {
int size = primearray.length;
primearray = new int[size+1];
primearray [size] = num;
System.out.println (num);
}
You created new array of prime number, primearray with size increased by 1, so primearray does not contain any old prime number, that will make wrong while checking prime. So you need to copy old prime numbers to new array.
And because the prime numbers start by 2, so your code should be:
Scanner sc = new Scanner(System.in);
System.out.print("Enter the upper limit: ");
int high = sc.nextInt();
int[] primeArray = new int[0];
for (int num = 2; num <= high; num++)
{
boolean isPrime = true;
for (int x : primeArray)
{
if (num % x == 0)
{
isPrime = false;
break;
}
}
if (isPrime == true)
{
primeArray = Arrays.copyOf(primeArray, primeArray.length + 1);
primeArray[primeArray.length - 1] = num;
System.out.println(num);
}
}

You should use a Sieve of Eratosthenes to find primes, rather than testing each number for divisibility; that method is far slower than sieving. Here is an implementation of sieving from my blog:
public static LinkedList sieve(int n)
{
BitSet b = new BitSet(n);
LinkedList ps = new LinkedList();
b.set(0,n);
for (int p=2; p<n; p++)
{
if (b.get(p))
{
ps.add(p);
for (int i=p+p; i<n; i+=p)
{
b.clear(i);
}
}
}
return ps;
}

As you say the key simplification is to only test primes when you find the next prime. For example:
public class PrimeGenerator {
private long current = 1;
private final List<Long> primes = new ArrayList<>();
public long next() {
do {
current++;
} while (primes.stream().anyMatch(n -> current % n == 0));
primes.add(current);
return current;
}
public LongStream stream() {
return LongStream.generate(this::next);
}
}
This records each prime as it is generated.
You can generate get all primes to a certain value with
generator.stream().takeWhile(p -> p < value)...

Previous answers already explains what is wrong with your code.
I just want to share another approach which is more efficient. The sample implementation is as per below. Basically, once we know x is prime number, we also know i*x is NOT a prime number. Further reading and visualization is available here
public int countPrimes(int n) {
if (n == 0 || n == 1) return 0;
int count = 0;
boolean[] check = new boolean[n+1];
for (int i = 2; i < n; i++) {
if (check[i]) continue;
for (int j = 1; j <= n / i; j++) {
check[j * i] = true;
}
count++;
}
return count;
}

Related

Why can I not enter large values (e.x. n = 100000) in this program that calculates all prime numbers from 0 to n inclusive?

I'm fairly new to coding, I just started learning Java this semester. I was messing around and created this java program that finds all prime numbers from 0 to n inclusive. It uses modulus and a nested for loop and outputs it in an arraylist. Now, I tested it with n = 5, n= 100, n = 1000 and n= 10000 and it worked completely fine and gave me accurate results, however when I inputted n = 100000, the console simply was blank and didnt give me any output at all. I realize that with large numbers it will take longer, so I was expecting to wait for it to number-crunch it all, but it just "gave up".
Is this the result of some calculation time-out? Is there a overide so I can calculate this with larger numbers? I realize this is not the most efficient code (i.e. there are calculations in the for loops that may be done twice) but thats not what the issue is here. The issue is why does a certain number stop output and is there any way to bypass this.
I put my code below, separated into two blocks because I have it in two different classes.
Thanks :)
General.java
import java.util.ArrayList;
import java.util.Scanner;
public class General
{
public static void main(String[] args)
{
Scanner number = new Scanner(System.in);
ArrayList<Integer> result = new ArrayList<Integer>();
System.out.print("What is the number you want to find all the primes that are smaller than it: ");
long n = number.nextInt();
PrimeNumberSeeker pNS = new PrimeNumberSeeker();
result = pNS.PrimesFromZero(n);
for (int m = 0; m < result.size(); m++)
{
System.out.print(result.get(m));
if (m+1 >= (result.size()))
System.out.print(".");
else
System.out.print(", ");
}
}
}
PrimeNumberSeeker.java
import java.util.ArrayList;
public class PrimeNumberSeeker
{
ArrayList<Integer> primes = new ArrayList<Integer>();
public ArrayList<Integer> PrimesFromZero(long n)
{
for (int i = 0; i <= n; i++) //selects all numbers from 0 - n inclusive
{
int check = 0;
//System.out.println(i);
for (int j = 1; j <= i; j++) //we make sure not to include 1 and itself (n)
{
if (i % j == 0)
check += 1;
//System.out.println(i + " " + j);
}
if (check == 2)
primes.add(i);
}
return primes;
}
}
It is just a problem of computational complexity, your algorithm could be optimized under different aspects to lower its complexity:
you don't need the check variable
you can limit the j range from 2 to sqrt(i)
if i%j==0 you can stop your investigation on i: it is not prime
Other advice:
always use parenthesis
use lowerCamelCase for functions' names
don't mix ints and longs, for your purposes ints are enough
This algorithm is not the best but works well with numbers up to 10.000.000 (or something more):
class PrimeNumberSeeker {
public ArrayList<Integer> primesFromZero(int n) {
ArrayList<Integer> primes = new ArrayList<Integer>();
for (int i = 1; i <= n; i++) {
boolean isPrime = true; // say your number is prime (we'll verify)
for (int j = 2; j <= Math.sqrt(i); j++) { // verify if it really is
if (i % j == 0) {
isPrime = false; // it isn't
break; // no more checks are needed, go out from this for cycle
}
}
if (isPrime) { // if isPrime is still true then i is prime
primes.add(i);
}
}
return primes;
}
}
Your program is running. I just tested it. You can visualize the progress by printing every found prime imediatly:
if (check == 2) {
primes.add(i);
System.out.println(i);
}
What you can also see, is that the progress becomes slower the bigger the numbers get. That is because your rumtime complexity is O(n^2) (squared). For each number you test each number that is lower. That means if you go from n=10.000 to n=100.000 your programm needs far more than 10 times the time.
For prime calculation check out the algorithm Sieve of Eratosthenes. This is far more efficient in terms of calculation time.

How to randomly generate integers between 0 to 3 without making them consecutive in Java?

So far I have managed to generate random numbers using Random.
for(int i=0; i<10; i++){
prevnum = num;
num = random.nextInt(4);
num = num==prevnum?ran.nextInt(4):num;
System.out.println("random number: " + num);
}
I do not want consecutive repeats, what should I do?
EDIT/SOLUTION:
I solved the issue using this workaround.
By checking if it was running for the first time to avoid nullpointerexception.
And the just used an ArrayList to remove any chances of repitition by removing the previous randomly generated number from the small pool/range.
public void printRandom(){
for(int i=0; i<10; i++){
if(firstrun){
firstrun=false;
num = random.nextInt(4);
System.out.println(num);
} else{
num = getRandom(num);
System.out.println(num);
}
}
}
int getRandom(int prevNum){
ArrayList choices = new ArrayList(Arrays.asList(0, 1, 2, 3));
choices.remove(prevNum);
return (int) choices.get(random.nextInt(3));
}
You better to get a random number until it would be different with the last number, not just once, in other words repeat this condition:
num = num==prevnum?ran.nextInt(4):num;
like:
do {
num = num==prevnum?ran.nextInt(4):num;
while (num != prevnum);
because your numbers are few, they might be the same, so check it more than once if it is needed.
Try this
Random ran = new Random();
int cur, pre = ran.nextInt(4);
for (int i = 0; i < 10; i++) {
cur = ran.nextInt(4);
while (cur == pre) {
cur = ran.nextInt(4);
}
pre = cur;
System.out.println(cur);
}
If you do not want a consecutive repeat, then you always want the gap between two consecutive numbers to be non-zero. That you suggests you pick your first number normally, and from that point on you pick a random, but non-zero, gap. Add the gap to the previous number to get the next number, which will always be different.
Some pseudocode:
// First random number.
currentNum <- random(4);
print(currentNum);
// The rest of the random numbers.
repeat
gap <- 1 + random(3);
currentNum <- (currentNum + gap) MOD 4;
print(currentNum);
until enough numbers;

Reversal of an Integer to check for Palindromic Number

I've looked at a few different stack questions and googled, but nothing I've read really has dealt with reversal of integers, but just strings.
So right now my code may or may not work at all, and it may be the dumbest thing you've ever seen, and that's okay and corrections are welcomed, but from what I hope my code will be doing is going through 100 - 999 multiplying the two ints and then checking whether it's palindromic or not. The if with reverse.equals(sum) is totally pseudocode and obviously won't work, however I can't figure out how to do a check for a palindromic int. Is there a simple way to do this? I've read some pretty lengthy and complicated ways, but I'm sure there's gotta be a simple way. Maybe not. :/. Anyway, here's my code.
public class PalandromicNum {
public static void main(String[] args){
int numOne = 100;
int numTwo = 100;
int toteVal;
int counter = 1000;
int sum = 0;
int finalSum = 0;
for(int i=0; i<counter; i++){
toteVal = numOne * numTwo;
numTwo++;
if(numTwo == 999){
numOne++;
numTwo = 100;
}
if(toteVal < sum){
sum += toteVal;
if(reverse.equals(sum)){
finalSum = sum;
System.out.println(finalSum);
}
}
}
}
}
Thanks again in advance!
This is on my phone so sorry for any errors.
Convert your number to a String and:
public static boolean isPalindrome(String str)
{
// base recursive case
if (str.length <= 1) {
return true;
}
// test the first and last characters
char firstChar = str.charAt(0);
char lastChar = str.charAt(str.length - 1) // subtract 1 as indexes are 0 based
if (!firstChar.equals(lastChar)) {
return false;
}
// if the string is longer than 2 chars and both are equal then recursively call with a shorter version
// start at 2nd char, end at char before last
return isPalindrome(str.substring(1,str.length);
}
Reversing integers is quite easy. Remember mod 10 gives u last digit. Loop over it, chopping off last digit of the number one at a time and adding it to reverse to new number. Then its matter of simple integer equality
int rev = 0;
int n = sum;
while(n)
{
rev = rev*10 + n%10;
n /= 10;
}
if(sum==rev)
//palindrome
else
//no no no no.
You can create a function named isPalindrome to check whether a number is a palindrome.
Use this function in your code.
You just need to pass the number you want to check into this function.
If the result is true, then the number is a palindrome.
Else, it is not a palindrome.
public static boolean isPalindrome(int number) {
int palindrome = number; // copied number into variable
int reverse = 0;
while (palindrome != 0) {
int remainder = palindrome % 10;
reverse = reverse * 10 + remainder;
palindrome = palindrome / 10;
}
// if original and reverse of number is equal means
// number is palindrome in Java
if (number == reverse) {
return true;
}
return false;
}
}
I believe that this code should help you out if you are trying to find out how many palindromes are between 100-999. Of course, it will count palindromes twice since it looks at both permutations of the palindromes. If I were you I would start creating methods to complete a majority of your work as it makes debugging much easier.
int total = 100;
StringBuilder stringSumForward;
StringBuilder stringSumBackward;
int numberOfPals = 0;
for(int i = 100; i < 999; i++){
for(int j = 100; j < 999; j++){
total = i * j;
stringSumForward = new StringBuilder(String.valueOf(total));
stringSumBackward = new StringBuilder(String.valueOf(total)).reverse();
if(stringSumForward.toString().equals(stringSumBackward.toString())){
numberOfPals++;
}
}
}

Attempting to create chance calculator

I am relatively new to Java and wanted to try and make a code that would randomly generate 2 numbers a set amount of times, and it would track how many times the 2 numbers are the same. Then after X amount of attempts it would calculate the chance of it happening.
# of randoms divided by times they were the same
import java.util.Random;
public class RandomTest {
public static void main(String[] args) {
int[] anArray;
anArray = new int[100000];
Random randomGenerator = new Random();
for (int loop = 1; loop < 1000; loop++) {
int random1 = randomGenerator.nextInt(100);
int random2 = randomGenerator.nextInt(100);
if (random1 == random2) {
int number = number + 1;
countArray[number] = loop;
}
if (loop == 1000) {
System.out.println("Took " + loop + " randoms.");
break;
}
else {}
}
}
}
Main issue seems to be getting array to fill and to get ints in/out of the loop.
Here is my version of your code:
import java.util.Random;
import java.util.ArrayList;
public class RandomTest {
public static void main(String[] args) {
ArrayList<Integer> duplicates = new ArrayList<Integer>();
int random1 = 0, random2 = 0;
Random randomGenerator = new Random();
for (int loop = 1; loop <= 1000; loop++) {
random1 = randomGenerator.nextInt(100);
random2 = randomGenerator.nextInt(100);
if (random1 == random2) {
duplicates.add(new Integer(random1));
}
}
for (Integer i : duplicates) {
System.out.println("Duplicate: "+i.toString());
}
}
}
There are a number of problems that your solution contains:
int number = number + 1;
The above will create a new int called number and give it the value null + 1, this is because the above can be split into 2 lines:
int num;
num = num + 1;
The first line will reserve memory space for a variable called num. The second line will try and put the value of (num + 1) into num. As we are calling num and it has not been initialised - this will give us a java.lang.Error (at least that is what I got).
So as you can see, putting number outside the for loop and initialising it like this:
int number = 0;
for (int loop = 1; loop <= 1000; loop++) {
number = number + 1;
}
Will increment the value of number by 1, 999 times.
Which brings me to the next point. The for loop will never make loop = 1000 because the condition will stop the loop before the condition is true, so when the for loop finishes, loop will equal 999. If you wanted the loop to finish on loop = 1000 you should use loop <= 1000. Also, the if condition is not necessary as when the loop finishes it will just carry on with the rest of the code beneath it.
I haven't used number at all in my solution, this is because I used an ArrayList, which is essentially a much more advanced version of an array that can grow dynamically and do loads of other cool stuff. Unfortunately ArrayLists need to contain objects, so I wrap each int inside an Integer object and this is fine. At the end I use a for loop to iterate through the duplicates list, for each result I print it out.
Hope this helps and if you have any questions feel free to comment beneath.
You probably want to do something about this line:
int number = number + 1;
To step through the array, set number to zero
int number = 0;
before entering the loop then increment number with
number = number + 1;

there is no output on calculating prime number

i want to print first 100 prime numbers. so, i created an array of int 100. I added first prime, bag[0] = 2, then for the following numbers, I tried to write an algorithm. It will start from 3 and goes on until array is full. Every number is decided to be if it is prime by whether it is divisible by the previous elements in array and if it is prime then it will be added to array.
here is my code:
public class Trial02
{
public static void main( String[] args)
{
int[] bag = new int[100];
bag[0] = 2; //first element of prime array
int valid = 1;
int i;
boolean result = true;
String str = "";
//starting from 3 it checks if a number is prime until array is full
for( i=3; valid<bag.length; i++)
{
//it checks if previous primes in array are divisible by current number until coming to current number
for(int k=0; k<valid; k++)
{
if( i % bag[k] == 0)
result = false;
}
if( result == true) //if it is prime it is added to array
{
bag[valid] = i;
valid ++;
}
}
//printing results
for(int m=0; m < bag.length; m++)
str = str + bag[m] + " ";
System.out.println("zaa xd");
System.out.println(str);
}
}
but it don't give any output, just a blank. I couldn't find where my mistake is.
Thanks in advance.
You're never actually checking if a number is prime or not (result isn't being set anywhere useful)
It looks like you need to reset result = true; inside the first for loop. Your code as posted sets result = false and then never changes it.
The most obvious error is that your boolean result = true; is outside the loop: once set to false, it never gets set back to true. You do not see any output because your program never stops.
As a side note, you do not need to check all primes all the way to the last one you've discovered: you can stop once you reach the square root of the candidate prime, i.e. i*i > bag[k]. You are not going to notice any effect when your limit is 100, but if you try 100000, it would help a lot more.
Your logic for determining the first 100 prime numbers is incorrect. And number of logical errors are present as indicated by others. I have re-written your code but not tested. I guess it will work:
public class Trial02
{
public static void main( String[] args)
{
int[] bag = new int[100];
bag[0] = 2; //first element of prime array
int valid = 1;
int i;
boolean isPrime = true;
String str = "";
//starting from 3 it checks if a number is prime until array is full
for( i=3; valid<bag.length; i++)
{
isPrime = true;
for (int k = 2; k < i; k++)
{
if (i % k == 0)
{
isPrime = false;
break;
}
}
if (isPrime == true)
{
bag[valid++] = i;
}
}
//printing results
for(i=0; i < bag.length; i++)
str = str + bag[i] + " ";
System.out.println("zaa xd");
System.out.println(str);
}
}
You have a number of logical mistakes in your code.
First you have a for loop that has a finalization case unrelated to its indexer. While this is valid, it makes the code harder to understand.
More importantly, result is only ever set to false, not true, so thus the loop will run forever, as valid is never changed.

Categories