64 lines
2.1 KiB
Elixir
64 lines
2.1 KiB
Elixir
defmodule PrimesSoEMap do
|
|
@typep stt :: {integer, integer, integer, Enumerable.integer, %{integer => integer}}
|
|
|
|
@spec advance(stt) :: stt
|
|
defp advance {n, bp, q, bps?, map} do
|
|
bps = if bps? === nil do Stream.drop(oddprms(), 1) else bps? end
|
|
nn = n + 2
|
|
if nn >= q do
|
|
inc = bp + bp
|
|
nbps = bps |> Stream.drop(1)
|
|
[nbp] = nbps |> Enum.take(1)
|
|
advance {nn, nbp, nbp * nbp, nbps, map |> Map.put(nn + inc, inc)}
|
|
else if Map.has_key?(map, nn) do
|
|
{inc, rmap} = Map.pop(map, nn)
|
|
[next] =
|
|
Stream.iterate(nn + inc, &(&1 + inc))
|
|
|> Stream.drop_while(&(Map.has_key?(rmap, &1))) |> Enum.take(1)
|
|
advance {nn, bp, q, bps, Map.put(rmap, next, inc)}
|
|
else
|
|
{nn, bp, q, bps, map}
|
|
end end
|
|
end
|
|
|
|
@spec oddprms() :: Enumerable.integer
|
|
defp oddprms do # put first base prime cull seq in Map so never empty
|
|
# advance base odd primes to 5 when initialized
|
|
init = {7, 5, 25, nil, %{9 => 6}}
|
|
[3, 5] # to avoid race, preseed with the first 2 elements...
|
|
|> Stream.concat(
|
|
Stream.iterate(init, &(advance &1))
|
|
|> Stream.map(fn {p,_,_,_,_} -> p end))
|
|
end
|
|
|
|
@spec primes() :: Enumerable.integer
|
|
def primes do
|
|
Stream.concat([2], oddprms())
|
|
end
|
|
|
|
end
|
|
|
|
IO.write "The first 20 primes are:\n( "
|
|
PrimesSoEMap.primes() |> Stream.take(20) |> Enum.each(&(IO.write "#{&1} "))
|
|
IO.puts ")"
|
|
IO.write "The primes between 100 to 150 are:\n( "
|
|
PrimesSoEMap.primes() |> Stream.drop_while(&(&1<100))
|
|
|> Stream.take_while(&(&1<150)) |> Enum.each(&(IO.write "#{&1} "))
|
|
IO.puts ")"
|
|
IO.write "The number of primes between 7700 and 8000 is: "
|
|
PrimesSoEMap.primes() |> Stream.drop_while(&(&1<7700))
|
|
|> Stream.take_while(&(&1<8000)) |> Enum.count |> IO.puts
|
|
IO.write "The 10,000th prime is: "
|
|
PrimesSoEMap.primes() |> Stream.drop(9999)
|
|
|> Enum.take(1) |> List.first |>IO.puts
|
|
IO.write "The sum of all the priems to two million is: "
|
|
testfunc =
|
|
fn () ->
|
|
ans =
|
|
PrimesSoEMap.primes() |> Stream.take_while(&(&1<=2000000))
|
|
|> Enum.sum() |> IO.puts
|
|
ans end
|
|
:timer.tc(testfunc)
|
|
|> (fn {t,_} ->
|
|
IO.puts "This test bench took #{t} microseconds." end).()
|