Created
February 5, 2020 04:26
-
-
Save lyo5ha/44679f8bbc539d5650d769acd2844f8f to your computer and use it in GitHub Desktop.
Jacobi symbol calculation on Elixir language.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Jacobian do | |
@moduledoc """ | |
Module for calculating Jacobian symbol a/n | |
""" | |
# iex> Jacobian.calculate(27, 101) | |
# => -1 | |
# iex> Jacobian.calculate(45, 1345) | |
# => 0 | |
# iex> Jacobian.calculate(2723, 4354655) | |
# => 1 | |
def calculate(a, n) do | |
cond do | |
a == 0 -> 0 | |
n > a and Integer.mod(n, 2) == 1 -> | |
pid = start_state(a, n) | |
result = main_loop(pid) | |
stop_state(pid) | |
result | |
end | |
end | |
defp main_loop(pid) do | |
case a_get(pid) != 0 do | |
true -> | |
second_loop(pid) | |
false -> | |
if n_get(pid) == 1 do | |
ans_get(pid) | |
else | |
0 | |
end | |
end | |
end | |
defp second_loop(pid) do | |
case Integer.mod(a_get(pid), 2) == 0 do | |
true -> | |
a_put(pid, div(a_get(pid), 2)) | |
r = Integer.mod(n_get(pid), 8) | |
if r == 3 or r == 5 do | |
ans_swap(pid) | |
end | |
second_loop(pid) | |
false -> | |
an_swap(pid, a_get(pid), n_get(pid)) | |
x = Integer.mod(a_get(pid), 4) | |
y = Integer.mod(n_get(pid), 4) | |
if x == y and y == 3 do | |
ans_swap(pid) | |
end | |
a_put(pid, Integer.mod(a_get(pid), n_get(pid))) | |
main_loop(pid) | |
end | |
end | |
# State management | |
defp start_state(a, n) do | |
{:ok, pid} = Agent.start_link(fn() -> %{ans: 1, a: a, n: n} end) | |
pid | |
end | |
defp ans_swap(pid) do | |
Agent.update(pid, fn(map) -> Map.put(map, :ans, -(map[:ans])) end) | |
end | |
defp ans_get(pid) do | |
Agent.get(pid, fn(%{ans: ans}) -> ans end) | |
end | |
defp a_get(pid) do | |
Agent.get(pid, fn(map) -> Map.get(map, :a) end) | |
end | |
defp a_put(pid, a) do | |
Agent.update(pid, fn(map) -> Map.put(map, :a, a) end) | |
end | |
defp n_put(pid, n) do | |
Agent.update(pid, fn(map) -> Map.put(map, :n, n) end) | |
end | |
defp n_get(pid) do | |
Agent.get(pid, fn(map) -> Map.get(map, :n) end) | |
end | |
defp an_swap(pid, a, n) do | |
a_put(pid, n) | |
n_put(pid, a) | |
end | |
defp stop_state(pid) do | |
Agent.stop(pid) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment