Improve on the original prime to beat the sieve alorithm

main
trivernis 10 months ago
parent a33ff440d0
commit 37337b3ea7
Signed by: Trivernis
GPG Key ID: 7E6D18B61C8D2F4B

@ -1,31 +1,43 @@
app "prime2" app "prime2"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" }
imports [pf.Stdout, pf.Task] imports [pf.Stdout, pf.Task, pf.Arg]
provides [main] to pf provides [main] to pf
main : Task.Task {} I32 main : Task.Task {} I32
main = main =
max <- Task.await parseArg
numStrings = numStrings =
primesIn 50_000_000 primesIn max
|> List.map Num.toStr |> List.map Num.toStr
|> Str.joinWith "\n" |> Str.joinWith "\n"
Stdout.line "$(numStrings)" Stdout.line "$(numStrings)"
parseArg =
args <- Task.await (Arg.list)
arg =
args
|> List.get 1
|> Result.withDefault "50_000_000"
|> Str.toU64
when arg is
Ok a -> a |> Task.ok
Err InvalidNumStr -> crash "Passed argument is not a numberr"
primesIn : U64 -> List U64 primesIn : U64 -> List U64
primesIn = \n -> primesIn = \n ->
numbers = List.concat [2] (List.range { start: At 3u64, end: At n, step: 2 }) numbers = List.concat [2] (List.range { start: At 3u64, end: At n, step: 2 })
primeSieve numbers primeSieve numbers n
primeSieve : List U64 -> List U64 primeSieve : List U64, U64 -> List U64
primeSieve = \l -> primeSieve = \l, max ->
when l is when l is
[] -> [] [] -> []
[a] -> [a] [a] -> [a]
[head, .., tail] if (Num.powInt head 2) > tail -> l [head, ..] if (Num.powInt head 2) > max -> l
[head, .. as tail] -> [head, .. as tail] ->
filteredList = List.dropIf tail (\e -> Num.isMultipleOf e head) filteredList = List.dropIf tail (\e -> Num.isMultipleOf e head)
List.concat [head] (primeSieve filteredList) List.concat [head] (primeSieve filteredList max)
countPrimesIn : U64 -> Nat countPrimesIn : U64 -> Nat
countPrimesIn = \limit -> countPrimesIn = \limit ->
@ -40,7 +52,6 @@ countPrimesIn = \limit ->
List.range { start: At 3, end: At (Num.ceiling (Num.sqrt (Num.toF64 n))), step: 2 } List.range { start: At 3, end: At (Num.ceiling (Num.sqrt (Num.toF64 n))), step: 2 }
|> List.any \a -> Num.isMultipleOf n a |> List.any \a -> Num.isMultipleOf n a
|> Bool.not |> Bool.not
res res
expect expect

@ -1,73 +1,62 @@
app "prime" app "prime"
packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" } packages { pf: "https://github.com/roc-lang/basic-cli/releases/download/0.7.1/Icc3xJoIixF3hCcfXrDwLCu4wQHtNdPyoJkEbkgIElA.tar.br" }
imports [pf.Stdout, pf.Task] imports [pf.Stdout, pf.Task, pf.Arg]
provides [main] to pf provides [main] to pf
main : Task.Task {} I32 main : Task.Task {} I32
main = main =
max <- Task.await parseArg
numStrings = numStrings =
primesIn 50_000_000 primesIn max
|> List.map Num.toStr |> List.map Num.toStr
|> Str.joinWith "\n" |> Str.joinWith "\n"
Stdout.line "$(numStrings)" Stdout.line "$(numStrings)"
primesIn : U64 -> List U64 parseArg =
primesIn = \n -> args <- Task.await (Arg.list)
List.range { start: At 0u64, end: At n } arg =
|> List.map \e -> isPrimePre e args
|> List.walk [] primeWalk |> List.get 1
|> Result.withDefault "50_000_000"
|> Str.toU64
when arg is
Ok a -> a |> Task.ok
Err InvalidNumStr -> crash "Passed argument is not a numberr"
PrimeResult : [No U64, Yes U64, Maybe U64] primesIn : U64 -> List U64
primesIn = \max ->
filterPrimesRec = \acc, l ->
when l is
[] -> acc
[head, .. as tail] if isPrimePost acc head ->
acc |> List.append head |> filterPrimesRec tail
primeWalk : List U64, PrimeResult -> List U64 [_, .. as tail] -> filterPrimesRec acc tail
primeWalk = \l, n -> [2]
when n is |> List.concat (List.range { start: At 3u64, end: At max, step: 2 })
Yes n2 -> |> \l -> filterPrimesRec [] l
List.append l n2
Maybe n2 -> isPrimePost = \list, n ->
if isPrimePost l n2 then isPrimeRec = \l, limit ->
List.append l n2 when l is
[_] -> Bool.true
[head, .. as tail] ->
if Num.isMultipleOf n head then
Bool.false
else if head > limit then
Bool.true
else else
l isPrimeRec tail limit
No _ -> l [] -> Bool.true
sqrtF = Num.sqrt (Num.toF32 n)
sqrtI = Num.floor sqrtF
isPrimePre : U64 -> PrimeResult if Num.isZero (sqrtF - Num.toF32 sqrtI) then
isPrimePre = \n -> Bool.false
if n < 2 then
No n
else if n < 4 then
Yes n
else if Num.isEven n then
No n
else if
(
firstPrimes
|> List.dropIf \p -> n < p
|> List.any \p -> Num.isMultipleOf n p
)
then
No n
else else
Maybe n isPrimeRec list (sqrtI + 1)
firstPrimes =
[2, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 51, 67, 71, 73, 79, 83, 89, 97]
isPrimePost : List U64, U64 -> Bool
isPrimePost = \l, n ->
nFloat = Num.toF32 n
valLimit = Num.ceiling (Num.sqrt nFloat)
# approximate the number of primes < sqrt(n) to limit the range we have to check with a 25% error tolerance
valLimitF = Num.toF32 valLimit
limit = Num.ceiling (valLimitF * 1.25 / (Num.log valLimitF))
l
|> List.sublist { start: 0, len: limit }
|> List.dropIf \p -> p > valLimit
|> List.any \p -> Num.isMultipleOf n p
|> Bool.not
countPrimesIn : U64 -> Nat countPrimesIn : U64 -> Nat
countPrimesIn = \limit -> countPrimesIn = \limit ->
@ -75,14 +64,26 @@ countPrimesIn = \limit ->
|> List.countIf \n -> |> List.countIf \n ->
if n < 4 then if n < 4 then
Bool.true Bool.true
else if n % 2 == 0 then else if Num.isEven n then
Bool.false Bool.false
else else
res =
List.range { start: At 3, end: At (Num.ceiling (Num.sqrt (Num.toF64 n))), step: 2 } List.range { start: At 3, end: At (Num.ceiling (Num.sqrt (Num.toF64 n))), step: 2 }
|> List.any \a -> Num.isMultipleOf n a |> List.any \a -> Num.isMultipleOf n a
|> Bool.not |> Bool.not
res expect
(
countPrimesIn 1000000
|> \expected ->
dbg expected
expected
)
== (
List.len (primesIn 1000000)
|> \actual ->
dbg actual
actual
expect countPrimesIn 10000 == List.len (primesIn 10000) )

Loading…
Cancel
Save