Skip to content

Instantly share code, notes, and snippets.

@somoza
Last active June 12, 2023 14:16
Show Gist options
  • Save somoza/02c50402ded7b47e49819a67a08cb47e to your computer and use it in GitHub Desktop.
Save somoza/02c50402ded7b47e49819a67a08cb47e to your computer and use it in GitHub Desktop.
Find prime numbers using Sieve of Atkin on Elixir
defmodule SieveOfAtkin do
def run(limit) do
sieve_range = 1..limit |> Enum.to_list()
sieve = 1..limit |> Enum.into(%{}, fn i -> {i + 1, false} end)
sieve = maybe_add_2_or_3(limit, sieve)
iterate_x(sieve_range, limit, sieve, sieve_range)
|> is_perfect_square(5, limit)
|> Enum.filter(fn {_i, value} -> value end)
|> Enum.count()
# |> Enum.map(fn {i, _value} -> i end)
# |> Enum.sort()
end
defp iterate_x([x | _tail], limit, sieve, _sieve_range) when x * x >= limit, do: sieve
defp iterate_x([], _limit, sieve, _sieve_range), do: sieve
defp iterate_x([x | tail], limit, sieve, sieve_range) do
iterate_y(sieve, x, tail, sieve_range, limit, sieve_range)
end
defp iterate_y(sieve, _x, tail_x, [], limit, sieve_range),
do: iterate_x(tail_x, limit, sieve, sieve_range)
defp iterate_y(sieve, _x, tail_x, [y | _tail], limit, sieve_range) when y * y >= limit,
do: iterate_x(tail_x, limit, sieve, sieve_range)
defp iterate_y(sieve, x, tail_x, [y | tail], limit, sieve_range) do
condition1(sieve, x, y, limit)
|> condition2(x, y, limit)
|> condition3(x, y, limit)
|> iterate_y(x, tail_x, tail, limit, sieve_range)
end
defp condition1(sieve, x, y, limit) do
# 4x² + y² = n
n = 4 * x * x + y * y
if(n <= limit and rem(n, 12) in [1, 5]) do
update_sieve(sieve, n)
else
sieve
end
end
defp condition2(sieve, x, y, limit) do
# 3x² + y²
n = 3 * x * x + y * y
if(n <= limit and rem(n, 12) == 7) do
if x == 5 and y == 10 do
end
update_sieve(sieve, n)
else
sieve
end
end
defp condition3(sieve, x, y, limit) do
# 3x² - y²
n = 3 * x * x - y * y
if(x > y and n <= limit and rem(n, 12) == 11) do
update_sieve(sieve, n)
else
sieve
end
end
defp update_sieve(sieve, n) do
# Invert the current value
Map.update(sieve, n, false, &(!&1))
end
defp is_perfect_square(sieve, r, limit) when r * r <= limit do
case sieve do
%{^r => true} ->
sieve =
Stream.unfold(r * r, fn x ->
if x <= limit, do: {x, x + r}
end)
|> Enum.reduce(sieve, fn i, sieve ->
Map.put(sieve, i, false)
end)
is_perfect_square(sieve, r + 1, limit)
_ ->
is_perfect_square(sieve, r + 1, limit)
end
end
defp is_perfect_square(sieve, _r, _limit), do: sieve
defp maybe_add_2_or_3(limit, sieve) when limit >= 3 do
update_sieve(sieve, 2)
|> update_sieve(3)
end
defp maybe_add_2_or_3(limit, sieve) when limit == 2, do: update_sieve(sieve, 2)
defp maybe_add_2_or_3(_limit, sieve), do: sieve
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment