Lecture 27: Prime Time

COSC 273: Parallel and Distributed Computing

Spring 2023

This Week

  • Homework 03 Due Friday
  • Final Project group & topic selection, also due Friday
    • Option 1: computing prime numbers
    • Option 2: sorting
    • Option 3: choose your own adventure

Computing Prime Numbers

Recall

The natural numbers $0, 1, 2, 3, \ldots$

Given natural numbers $n$, $d$:

  • $d$ divides $n$ if $n = d \cdot q$ for some natural number $q$
    • $q$ is the quotient of $n$ and $d$
    • $n$ is a multiple of $d$
  • $d$ is a proper divisor of $n$ if it is a divisor and $d \neq 1, n$

  • In Java
    • (n % d == 0) returns true if and only if d divides n

Proper divisors of 12? 13?

Prime Definitions

A natural number $p > 1$ is prime if it has no proper divisors.

  • A natural number $n > 1$ that is not prime is composite

Examples:

  • $2, 3, 5, 7, 11, 17, 19$ are prime

  • $4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20$ are composite

Who Cares?

  • Mathematicians
    • primes are atomic building blocks of natural numbers
    • understanding how prime numbers are distributed is a central goal of number theory
  • Computer Scientists
    • prime numbers are essential for RSA encryption
    • error correcting codes
  • Everyone
    • RSA encryption is most widely used public key encryption
    • used for secure communication everywhere

Final Project, Option 1

The Task. Generate an array int[] primes that contains every prime number that can be stored as an int in Java in increasing order.

  • Integer.MAX_VALUE = 2_147_483_647
  • there are $105,097,565$ primes up to this value
    • $\implies \sim$ 400 MB of primes!

Testing if a Number is Prime

Method 1: Trial Division

  • Check all numbers less than n to see if n is divisble by them:
public boolean isPrime(int n) {
    if (n <= 1) return false;
	
    for (int d = 2; d < n; ++d) {
        if (n % d == 0)
            return false;
    }
	
    return true;
}

Example

Is 91 prime?

Is Trial Division Efficient?

Can we improve trial division?

  • Do we have to check all possible divisors up to n-1?

Making Things More Efficient

Claim 1. If $n$ is composite, then it has a divisor $d$ with $d \leq \sqrt{n}$

Why?

Conclusion. Only need to check divisors up to $\sqrt{n}$

A Faster Procedure

public boolean isPrime(int n) {
    if (n <= 1) return false;
	
    for (int d = 2; d * d <= n; ++d) {
        if (n % d == 0)
            return false;
    }
	
    return true;
}

Can Procedure Be Improved More?

Claim 2. If $n$ is composite, then it has a prime divisor at most $\sqrt{n}$.

So we only need to check primes up to $\sqrt{n}$

Example:

  • To determine if a number less than…
    • …100 is prime, need only check divisibility by $2, 3, 5, 7$
    • …1,000 is prime, need only check divisibility by $2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31$
    • …1,000,000 is prime, need only check divisibility by primes up to 1,000

Generating Primes

Suppose we want to generate all primes up to $N$…

How should we do this?

Sieve of Eratosthenes

  1. Write numbers 2 through N
  2. Read numbers in order:
    • if a number is not crossed out, it is prime
    • then cross out all multiples

    02 03 04 05 06 07 08 09 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

Observation/Optimization

In SoE, once we find primes up to Math.sqrt(N), we can stop!

Why?

Eratosthenes in Code

  1. Make boolean array isPrime of size N
    • interpretation: isPrime[i] == true if i is prime
  2. Initialize isPrime[i] to true for all i >= 2
  3. Iterate over indices i up to Math.sqrt(N):
    • if isPrime[i]:
      • set isPrime[j] = false for all j that are multiples of i
    • otherwise, do nothing

When done: isPrime[i] is true precisely for prime i

Eratosthenes in Java

boolean[] isPrime = new boolean[N];
for (int i = 2; i < N; ++i) {
    isPrime[i] = true;
}
for (int i = 2; i < N; ++i) {
    if (isPrime[i]) {
        for (int j = 2 * i; j < N; j += i) {
            isPrime[j] = false;		
        }
    }
}

Activity

Let’s compute the primes up to $225 = 15^2$

To start, here are the primes up to 15:

  • $2, 3, 5, 7, 11, 13$

Primes up to 225:

1–44:

45–89:

90–134:

90–134:

135–179:

180–225:

Project Technical Challenges

  1. Storing boolean isPrime of size Integer.MAX_VALUE is already on the order of 1GB of memory

  2. How can we partition the problem to exploit parallelism?

    • multithreading?
    • vector operations?
  3. How to synchronize between different sub-tasks?