Skip to content

Instantly share code, notes, and snippets.

@madlep
Created June 22, 2022 01:54
Show Gist options
  • Save madlep/14f90bcef932129a2f4d61d6691143d2 to your computer and use it in GitHub Desktop.
Save madlep/14f90bcef932129a2f4d61d6691143d2 to your computer and use it in GitHub Desktop.
Given a Fibonacci number, give the previous Fibonacci number. If the number given is not a Fibonacci number, return -1.

Previous Fibonacci Number

Problem

Given a Fibonacci number, give the previous Fibonacci number. If the number given is not a Fibonacci number, return -1.

From rendezvous with cassidoo, June 20 2022

Code

defmodule Fib do
  @golden_ratio (1 + :math.sqrt(5)) / 2
  def prev(fib) do
    if fib?(fib), do: round(fib / @golden_ratio), else: -1
  end

  defp fib?(n) do
    # Binet's formula
    x = 5 * n ** 2
    square?(x + 4) or square?(x - 4)
  end

  defp square?(n) do
    x = :math.sqrt(n)
    floor(x) == x
  end
end

Tests

ExUnit.start(auto_run: false)

defmodule FibTest do
  use ExUnit.Case, async: false

  describe "prev/1" do
    test "returns 0 if n is 0" do
      assert Fib.prev(0) == 0
    end

    test "returns 1 if n is 1" do
      assert Fib.prev(1) == 1
    end

    test "returns previous fibonacci number if n is a fibonacci number" do
      [2, 3, 5, 8, 13, 21, 34, 55, 89, 144]
      |> Enum.reverse()
      |> Enum.chunk_every(2, 1, :discard)
      |> Enum.map(&List.to_tuple/1)
      |> Enum.each(fn {n, prev_n} -> assert Fib.prev(n) == prev_n end)
    end

    test "returns -1 if n is NOT a fibonacci number" do
      [4, 6, 7, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 22]
      |> Enum.each(fn n -> assert Fib.prev(n) == -1 end)
    end
  end
end

ExUnit.run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment