My initial goal when writing this was to leave the smallest footprint possible. I can say with confidence that this goal has been met. Unfortunately, this leaves me with a r
Just for funsies, let's take a look at this page.
pi(x) is the prime counting function, it returns the number of primes below x. You can approximate pi(x) using the following inequalities:
(x/log x)(1 + 0.992/log x) < pi(x) < (x/log x)(1 + 1.2762/log x)
// The upper bound holds for all x > 1
p(x) is the nth's prime function, which can be approximated using:
n ln n + n ln ln n - n < p(n) < n ln n + n ln ln n
// for n >= 6
With that in mind, here is a very fast generator which computes the first n primes, where each element at index i equal p(i). So, if we want to cap our array at primes below 2,000,000, we use the upperbound inequality for the prime counting function:
let rec is_prime (primes : int[]) i testPrime maxFactor =
if primes.[i] > maxFactor then true
else
if testPrime % primes.[i] = 0 then false
else is_prime primes (i + 1) testPrime maxFactor
let rec prime_n (primes : int[]) primeCount testPrime tog =
if primeCount < primes.Length then
let primeCount' =
if is_prime primes 2 testPrime (float testPrime |> sqrt |> int) then
primes.[primeCount] <- testPrime
primeCount + 1
else
primeCount
prime_n primes primeCount' (testPrime + tog) (6 - tog)
let getPrimes upTo =
let x = float upTo
let arraySize = int <| (x / log x) * (1.0 + 1.2762 / log x)
let primes = Array.zeroCreate (max arraySize 3)
primes.[0] <- 2
primes.[1] <- 3
primes.[2] <- 5
prime_n primes 3 7 4
primes
Cool! So how fast is it? On my 3.2ghz quad-core, I get the following in fsi:
> let primes = getPrimes 2000000;;
Real: 00:00:00.534, CPU: 00:00:00.546, GC gen0: 0, gen1: 0, gen2: 0
val primes : int [] =
[|2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71;
73; 79; 83; 89; 97; 101; 103; 107; 109; 113; 127; 131; 137; 139; 149; 151;
157; 163; 167; 173; 179; 181; 191; 193; 197; 199; 211; 223; 227; 229; 233;
239; 241; 251; 257; 263; 269; 271; 277; 281; 283; 293; 307; 311; 313; 317;
331; 337; 347; 349; 353; 359; 367; 373; 379; 383; 389; 397; 401; 409; 419;
421; 431; 433; 439; 443; 449; 457; 461; 463; 467; 479; 487; 491; 499; 503;
509; 521; 523; 541; ...|]
> printfn "total primes: %i. Last prime: %i" (primes.Length - 1) primes.[primes.Length - 1];;
total primes: 149973. Last prime: 2014853
So that's all the primes around 2 million in less than half a second :)