-1

I'm trying to write a program for the Sieve of Eratosthenes and it works but if the input number is 33 or greater I get this error:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
    at java.base/java.util.Objects.checkIndex(Objects.java:373)
    at java.base/java.util.ArrayList.get(ArrayList.java:425)
    at Main.main(Main.java:23)

this is the code that I used

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner read = new Scanner(System.in);
        int nr = read.nextInt();

        ArrayList<Integer> listA = new ArrayList<Integer>();
        ArrayList<Integer> listB = new ArrayList<Integer>();

        for (int i = 2; i <= nr; i++)
                listA.add(i);
        //System.out.println(listA);
        int m = 2;
        listB.add(m);
        while (m <= nr-2) {
            listA.removeAll(Arrays.asList(m));
            for (int j = m*2; j <= nr; j = j + m) {
                listA.removeAll(Arrays.asList(j));
            }
            m = listA.get(0);
            listB.add(m);
        }
        System.out.println(listB);

    }
}
hereToAsk
  • 11
  • 1
  • There is no need for `listA.removeAll(Arrays.asList(m));` since you are removing only one value. You can directly do `listA.remove(m)`. As far as the rest of your code goes I'm not really sure what you are trying to accomplish. You could just use a for loop and a boolean[] you don't need two ArrayLists – HomeIsWhereThePcIs Mar 15 '20 at 21:30
  • please indicate which line of your code is throwing the exception – Bohemian Mar 15 '20 at 22:45
  • btw, the simplest and fastest implementation is a giant `boolean[]`, but if your sieve is large (millions), use a `BitSet` which uses only 1 bit per value. – Bohemian Mar 15 '20 at 22:48

1 Answers1

1

When you get the java.lang.IndexOutOfBoundsException it means that at that point you have already removed all the numbers from listA, so you can't do listA.get(0)

I would declare an array of booleans and set them all to true. You can pretend these are numbers from 0-n.

Then set every non-prime number to false by starting with 2 and setting multiples to false, etc. Before multiplying you can check if that number is already set to false, that means multiplying this number is not necessary, since all multiples are already set to false. This makes the algorithm significantly faster.

Finally print out all the prime numbers starting from 2.

You could remove Arrays.fill to make it more efficient, but then you need to invert all the other logic, since boolean will default to false.

        boolean[] primeNumbers = new boolean[nr + 1];
        Arrays.fill(primeNumbers, true);

        int m = 2;
        while (m <= Math.sqrt(nr)) {
            if (primeNumbers[m])
                for (int j = m * 2; j <= nr; j = j + m) {
                    primeNumbers[j] = false;
                }
            m++;
        }

        for (int i = 2; i <= nr; i++) {
            if (primeNumbers[i]) System.out.println(i);
        }
HomeIsWhereThePcIs
  • 1,273
  • 1
  • 19
  • 37
  • 2
    Note that the actual limit is `root nr` (not `nr / 2`), since this allows you to skip checking for reverse order factors (ie, 2 * 17 -> 17 * 2). Note too that a good second optimization (in terms of speed and memory) is to simply exclude all even numbers, since all of them would be non-prime (barring 2, of course) - the array can be half the size. – Clockwork-Muse Mar 15 '20 at 22:07