|
|
@ -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)
|
|
|
|
)
|
|
|
|