Sieve of erastothenes primality issue - java

Set up to print out all false values which are prime numbers however out of 25 it prints. 3, 5, 7, 8, 9, 11, 13, 14, 15, 17, 19, 20, 21, 23, 24, not sure why some of them slip by. Any insight into the matter would be nice.
Or simply pointing me in the write direction.
Why are the non-prime numbers such as 8 being printed?
import java.util.Arrays;
import java.util.Scanner;
class Sieve {
public static void main(String args[]) {
Scanner inputScanner;
inputScanner = new Scanner(System.in);
//determine max value
System.out.println("I will determine all the primality of a set of numbers, enter the max");
int n = Integer.parseInt (inputScanner.nextLine());
boolean[] truedBooleanArray = calcBooleanMax (n);
//call upon function to check primality
boolean [] primeNumbers = calcPrimality (truedBooleanArray);
// call upon function to print out prime numbers
printPrimes(primeNumbers);
}
public static boolean[] calcBooleanMax(int maxNumber) {
boolean [] maxNumberArray = new boolean [maxNumber];
maxNumberArray[0] = false;
maxNumberArray[1] = false;
//asigns 1, 0 to false
//change all boleans within array from false to true!
for(int i=1; i < maxNumber; i++) {
maxNumberArray [i] = true;
}
return maxNumberArray;
}
public static boolean[] calcPrimality(boolean [] truedBooleans) {
for(int i = 2; i <=truedBooleans.length; i++) {
//check every number greater than 1 for primality.
if (truedBooleans[i-1]) {
}
//finds multiples and makes sure they arent stored
for(int j = 2*i; j <= truedBooleans.length; j+= i) {
truedBooleans[j-1] = false;
}
}
return truedBooleans;
}
public static void printPrimes(boolean [] thePrimeNumbers){
System.out.println("The prime numbers are [");
for(int i = 2; i<thePrimeNumbers.length; i++) {
if(thePrimeNumbers[i] == false ) {
System.out.print(i + ", ");
}
}
}
}

You have a few errors.
The array must be one larger than the given max
You are accidentally adding one back to the sieve when initializing
When removing multiples from the sieve, you must first make sure the initial number "i" is still in the sieve
You want to print the items that are still in the sieve, so print when true rather than false
Here is the fixed code
public static boolean[] calcBooleanMax(int maxNumber) {
boolean [] maxNumberArray = new boolean [maxNumber+1];
maxNumberArray[0] = false;
maxNumberArray[1] = false;
//asigns 1, 0 to false
//change all boleans within array from false to true!
for(int i=2;i < maxNumber+1; i++) {
maxNumberArray [i] = true;
}
return maxNumberArray;
}
public static boolean[] calcPrimality(boolean [] truedBooleans){
for(int i = 2; i <truedBooleans.length; i++) {
if(truedBooleans[i]) {
//finds multiples and makes sure they arent stored
for(int j = 2*i; j < truedBooleans.length; j+= i) {
truedBooleans[j] = false;
}
}
}
return truedBooleans;
}
public static void printPrimes(boolean [] thePrimeNumbers){
System.out.println("The prime numbers are [");
for(int i = 2;i<thePrimeNumbers.length;i++) {
if(thePrimeNumbers[i] ) {
System.out.print(i + ", ");
}
}
}

A simpler solution is a less literal interpretation of the algorithm. Rather than keeping a literal list of booleans, you can keep a list of the current primes. This makes the code simpler and easier to read.
Here is an example of a solution (that relies on Java 8 streams):
class Sieve {
private long current = 2;
private final List<Long> primes = new ArrayList<>();
public long nextPrime() {
while (primes.stream().anyMatch(p -> current % p == 0))
current++;
primes.add(current);
return current;
}
}

Related

Boolean assignment not catching, need to understand more

public class MyClass {
public static void main(String args[]) {
int[] nums = {1, 2, 9, 3, 4};
boolean results = false;
int end = nums.length;
if (end>4)end=4;
for (int x=0;x<end;x++)
{
System.out.println(nums[x]);
results = (nums[x] == 9);
}
System.out.println(results);
}
}
The following code checks to see if a 9 is present in the first 4 elements of an array, yet using the boolean operator in this fashion seems to always fail if there are not more than 1 "9" in the first 4 elements of the array.
Why is this? Logically it seems that this should work, and it really helps me to understand better when I understand why something doesn't work.
The reason is that you have itetate all the elements,the result will be the result of the last element,
So you need to stop for when you find the match result
for (int x=0;x<end;x++)
{
System.out.println(nums[x]);
if(nums[x] == 9){
result = true;
break;
}
}
You overwrite results every time. As written, this'll tell you whether the last item in the array equals 9 (which it doesn't), not whether any item in the array equals 9.
You should assign true to result if num[x] == 9; otherwise, don't assign anything.
#lucumt's answer shows an example of how to do that. One other example, just replace
results = (nums[x] == 9);
with
results |= (nums[x] == 9);
where the |= assignment is equivalent to results = results || (num[x] == 9); - in other words, if any value is true, the entire expression will be true. (Note that #lucumt's answer is slightly more efficient because it's O(n) whereas this is Theta(n) - i.e. this will always run exactly n times, where n is the length of the list, but #lucumt's can end the loop early if it finds any 9).
In your for loop you are over writing the value each time. This means you are testing if the 4th value is equal to 9.
you can solve your problem like so:
boolean results = false;
for (int x = 0; x < end; x++) {
System.out.println(nums[x]);
if(nums[x] == 9) {
results = true;
break;
}
}
Try this:
boolean isPresent(int[] nums, int val)
{
for (int x : nums )
{
if (nums[x] == val)
return true;
}
return false;
}
Otherwise you rewrite a value every time you're checking
I wrote you a class. The method nignPresentInFirst4Elements(int[] arr) returns true if the given array contains a 9 in one or more of it's first 4 elements:
public class Test {
private static boolean nignPresentInFirst4Elements(int[] arr) {
if(arr == null)
return false;
for(int i = 0; i < Math.min(arr.length, 4); i++) {
if(arr[i] == 9)
return true;
}
return false;
}
public static void main(String[] args) {
int[][] arrs = new int[][] {
{5, 8, 9, 3},
{5, 8, 9, 3, 8, 26},
{5, 8, 9, 9},
{5, 8, 23, 0}
};
for(int i = 0; i < arrs.length; i++) {
System.out.println(toString(arrs[i]) + " | " + nignPresentInFirst4Elements(arrs[i]));
}
}
private static String toString(int[] arr) {
if(arr == null)
return "null";
String s = "[";
if(arr.length > 0)
s += arr[0];
for(int i = 1; i < arr.length; i++) {
s += ", " + arr[i];
}
s += "]";
return s;
}
}

Method inefficiency

This is from code fights. The method works but is apparently taking too long for large inputs. Can someone please explain what is inefficient about this solution?
Question:
Given an array of integers, write a function that determines whether the array contains any duplicates. Your function should return true if any element appears at least twice in the array, and it should return false if every element is distinct.
Example
For a = [1, 2, 3, 1], the output should be
containsDuplicates(a) = true.
There are two 1s in the given array.
Solution:
static boolean containsDuplicates(int[] a) {
boolean elementRepeat = false;
for (int loop1 = 0; loop1 < a.length; loop1++){
for (int loop2 = 0; loop2 < a.length; loop2++){
if (a[loop1] == a[loop2] && loop1!=loop2){
elementRepeat = true;
return elementRepeat;
}
}
}
return elementRepeat;
}
One way to do this is by storing the array in Set and then comparing the length of the array and set. Here is how:
static boolean containsDuplicates(int[] array) {
HashSet<Integer> integers = new HashSet<>();
Arrays.stream(array).forEach(integers::add);
array.length == integers.size();
}
I think that #Henry did a very good sugestion.
This is an example:
import java.util.HashSet;
import java.util.Set;
public class Test4 {
public static void main(String[] args) {
Integer[] arrayInt = {1, 2, 3, 1};
Set<Integer> integers = new HashSet<Integer>();
boolean hasDuplicates = false;
for (Integer integerNumber : arrayInt) {
if (!integers.add(integerNumber)) {
hasDuplicates = true;
break;
}
}
System.out.println("Contains duplicates? " + hasDuplicates);
}
}
And it will print:
Contains duplicates? true

Prime number identification and squaring

I was asked to write code for the following Question,
Find the prime numbers in an array of given numbers and print the sum
of squares of the prime numbers found.
And this was my code:
import java.util.*;
public class primenumber2
{
public static void main(String[] args)
{
int[] int1 = {2,3,4,6,11,13,17,99};
int square=0;
int result=0;
boolean isprime = true;
for(int i=0;i<int1.length;i++)
{
int temp=int1[i];
for(int j=1;j<i;j++)
{
if(temp%j==0)
{
isprime = false;
}
else
isprime = true;
}
if(isprime)
{
System.out.println(temp);
square = temp*temp;
result = result+square;
}
}
System.out.println(result);
}
}
Now the problem is that every number that ends with 9,gets added as a prime,i couldn't find out why.
Can someone help me with this? and also if ,possible a better way to solve this problem just using the basic functions and classes.
2 problems
you start for-loop from 1
your check until j<i which is the index of the first loop.
for(int j=1;j<i;j++)
// ↑ why limit this loop at index of the outer loop?
// ↑ start at 1 (WRONG!)
To check primes, you must start with number % 2 until number % number - 1
for(int j=2;j<temp;j++)
But in order to clarify and save iterations, I would make a method to check primes like this:
private static boolean isPrime(int toCheck) {
for (int i = 2; i < toCheck; i++) {
// stop iterating if you know number is even
if (toCheck % i == 0) return false;
}
return true;
}
Then you can use it like:
public static void main(String[] args) throws Exception {
int[] int1 = { 2, 3, 4, 6, 11, 13, 17, 99 };
int square = 0;
int result = 0;
for (int i = 0; i < int1.length; i++) {
if (isPrime(int1[i])) {
System.out.println(int1[i]);
square = int1[i] * int1[i];
result += square;
}
}
System.out.println(result);
}
OUTPUT:
2
3
11
13
17
592
which seems correct

Checking to see if an integer has distinct numbers java

I'm having a difficult time with my program! For this method I have to check to see if all the numbers are distinct and I can't figure out for the life of me what I am doing wrong. I don't know if using an array is the best way to go. I must call the getDigit method.
for (int i = 0; i <= numDigits(number); i++) {
int digit = getDigit(number,i);
if (digit == getDigit(number,i)) {
return false;
}
}
return true;
You can first get each digit from the number and add them to a HashSet, then compare the size of HashSet with the number of digits present in the number
You can try this code:
public static void main(String[] args) {
int val = 123554;
Set<Integer> set = new HashSet<Integer>(); // HashSet contains only unique elements
int count = 0; // keeps track of number of digits encountered in the number
// code to get each digit from the number
while (val > 0) {
int tempVal = val % 10;
set.add(tempVal); // add each digit to the hash set
// you can have a boolean check like if(!set.add(tempVal)) return false; because add() returns false if the element is already present in the set.
val = val / 10;
count++;
}
if (count == set.size()) {
System.out.println("duplicate digit not present");
} else {
System.out.println("duplicate digit present");
}
}
Splitting Int into single digits:
Use something similar to this:
Code to print the numbers in the correct order:
int number; // = and int
LinkedList<Integer> stack = new LinkedList<Integer>();
while (number > 0) {
stack.push( number % 10 );
number = number / 10;
}
while (!stack.isEmpty()) {
print(stack.pop());
}
Source
Checking for Duplicates:
Again, something similar to this:
public static boolean duplicates (int [] x, int numElementsInX ) {
Set<Integer> set = new HashSet<Integer>();
for ( int i = 0; i < numElementsInX; ++i ) {
if ( set.contains( x[i])) {
return true;
}
else {
set.add(x[i]);
}
}
return false;
}
Source
Alternative
If you can split the array, an alternative could be to use:
int[] numbers = { 1, 5, 23, 2, 1, 6, 3, 1, 8, 12, 3 };
Arrays.sort(numbers);
for(int i = 1; i < numbers.length; i++) {
if(numbers[i] == numbers[i - 1]) {
System.out.println("Duplicate: " + numbers[i]);
}
}
i suppose that you want to compare for example the number 12345 with 23145, and prompt out a false, and if they are the same (digit by digit, prompt a true) , am i right?.
If you want to do this, you should make 2 arrays and you have to make sure to compare each position of both so you can compare digit by digit.
Hope it helps you
public boolean unique(int theNumber) {
String number = new Integer(theNumber).toString();
Set<Character> set = new LinkedHashSet<Character>();
for(char c:number.toCharArray()) {
set.add(Character.valueOf(c));
}
return number.length() == set.size();
}

java random number chooser

I have a homework to write a method that returns a random number between
1 and 54, excluding the numbers passed in the argument. The method header is
specified as follows:
public static int getRandom(int... numbers)
I can't use anything more advanced than Single-Dimensional Arrays.
my code is:
public class PE13RandomNumberChooserVer2 {
public static void main(String[] args) {
int[] excludeNumbers = {1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18};
int randomNumber = getRandom(excludeNumbers);
System.out.println();
System.out.println("Random number chosen: " + randomNumber);
}
public static int getRandom(int... excludeNumbers) {
int random = 1 + (int)(Math.random() * (54 - 1) + 1);
System.out.println("Numbers to exclude: ");
for (int i = 0; i < excludeNumbers.length; i++) {
System.out.print(excludeNumbers[i] + " ");
while (excludeNumbers[i] == random) {
random = 1 + (int)(Math.random() * 54);
System.out.println("\n(for test only) next random number: " + random);
}
}
return random;
}
}
a sample run showed that my logic is wrong:
(for test only) initial random number: 8
Numbers to exclude:
1 2 3 4 5 6 7 8
(for test only) next random number: 12
11 12
(for test only) next random number: 3
13 14 15 16 17 18
Random number chosen: 3
it checks only if random is equal to the current item in the array, it doesn't consider the case in which it can be equal to the previous item in the list that is already checked.
The end result for the random generated number should be a value different from the numbers in the array.
Any suggestions how to fix it are greatly appreciated.
The following will do it:
private final Random rand = new Random();
public int getRandom(int min, int max, int... excludeNumbers) {
int random = rand.nextInt(max - min + 1 - excludeNumbers.length) + min;
for (int exc : excludeNumbers) {
if (random >= exc) {
random++;
}
}
return random;
}
Observe how it only generates a single random number and doesn't require a rejection loop.
Note that both min and max are inclusive. Also note that excludeNumbers must appear in ascending order.
This
int random = 1 + (int)(Math.random() * (54 - 1) + 1);
and this
random = 1 + (int)(Math.random() * 54);
are strange and should coincide.
Latter one is correct.
Next your loops are wrong. Loops are for regenerating number in case it coincides with prohibited one. So you should place for inside while and place println outside all loops. for should serve to check all prohibited numbers for one generated and while should server as retriement loop.
Also you can use Random class.
THE CODE
public static void main(String[] args) {
int[] excludeNumbers = {1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18};
int randomNumber;
System.out.println("Numbers to exclude: ");
for (int i = 0; i < excludeNumbers.length; i++) {
System.out.print(excludeNumbers[i] + " ");
}
// 100 tests
for(int i=0; i<100; ++i ) {
randomNumber = getRandom(excludeNumbers);
System.out.println();
System.out.println("Random number chosen: " + randomNumber);
}
}
public static int getRandom(int... excludeNumbers) {
int random;
// regeneration loop
regeneration: while(true) {
// generating a number
random = 1 + (int)(Math.random() * 54);
// checking of it's correctness
for (int i = 0; i < excludeNumbers.length; i++) {
// checking if number conincides for prohibited
if( excludeNumbers[i] == random ) {
// if number concided, then going to regeneration
continue regeneration;
}
// here number has not coincided
// but with just one of prohibites
// no decision here
}
// here all prohibited numbers checked and
// no coincidences found
// so generated number is good
System.out.println("\n(for test only) next random number: " + random);
break regeneration;
}
return random;
}
Try this, which simply keeps trying until you get an acceptable number.
List<Integer> nums = Arrays.asList(excludedNumbers);
while (true) {
Random random = 1 + (int)(Math.random() * 54);
if (!nums.contains(random))
return random;
}
The method would be cleaner if you passed exclude numbers as a list.
The techniques that keep retrying until hitting an allowed number are crude and turn into a crying misery as the number of allowed numbers approaches 1. A much more elegant way is this:
create a boolean[54];
set each excluded element to true;
choose a random number r from a range as large as the number of allowed choices (54 - number of exclusions);
return the rth false element in the boolean array.
Note: this algorithm is the best fit when you can cache the boolean array; for your exact case (the function receives a new array every time) NPE's solution is superior.
Look into java.util.random, it has a method that provides a random integer between 0 and your specified number. I can't give you an example because I'm typing this from my phone at the moment, but if you were to get it between 1 and 54 I would get a random number between 0 and 53 and add 1 to the result.
I am also teaching myself Java right now. I spend several days on this problem already while there is no answer available yet online. The solution above is too advanced for me so far. Here is my solution finally, which employ basic array knowledge only
public class Q6_13 {
public static void main(String[] args) {
int[] excludeNumbers = {1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18};
System.out.println (getRandom(excludeNumbers));
}
public static int getRandom(int...numbers) {
int n = (int)(Math.random() * 54) + 1; ;
boolean newRandom = false;
boolean getNew = false;
while (getNew == false) {
for (int i = 0; (i < numbers.length) && newRandom == false; i++) {
if (n == numbers[i]) {
newRandom = true;
}
}
if (newRandom) {
n = (int)(Math.random() * 54) + 1;
getNew = false;
newRandom = false;
}
else
getNew = true;
}
return n;
}
}
public static int getRandom(int... numbers) {
final Random random = new Random();
final int[] arr1 = new int[54];
int count = 54;
for(int i = 0; i < arr1.length; ++i) {
arr1[i] = i + 1; // good luck doing this with foreach
}
for(int i = 0; i < numbers.length; ++i) {
final int n = numbers[i];
if(arr1[n] != 0) {
--count;
}
arr1[n] = 0;
}
final int[] arr2 = new int[count];
for(int i = 0, j = 0; i < arr2.length; ++i, ++j) {
if(arr1[j] == 0) {
++j;
}
else {
arr2[i] = arr1[j];
}
}
return arr2[random.nextInt(count)];
}
public class Compute {
public static void main(String[] args) {
int[] values = {2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41};
int x = 1+ (int) (Math.random()*54);
System.out.println("Value: "+getRandom(x,values));
}
public static int getRandom(int a, int... numbers){
System.out.println("x1: "+a);
for(int j=0;j<numbers.length;){
//System.out.println("Numbers: "+numbers[j]);
if(numbers[j]==a){
a = 1 + (int) (Math.random()*54);
System.out.println("x2: "+a);
j=0;
continue;
}
j++;
}
return a;
}
}

Categories