Skip to content

Instantly share code, notes, and snippets.

@nhomble
Created June 30, 2017 04:52
Show Gist options
  • Save nhomble/faf08174a5f27aa3ebfd7917e38742f4 to your computer and use it in GitHub Desktop.
Save nhomble/faf08174a5f27aa3ebfd7917e38742f4 to your computer and use it in GitHub Desktop.
class FibCoder:
'''
https://en.wikipedia.org/wiki/Fibonacci_coding
'''
def __init__(self, seed: int = 2):
self._fib = []
self._fibonacci(seed)
def _next_fib(self, n: int):
i = 0
while self._fibonacci(i) <= n:
i += 1
return i - 1
def _fibonacci(self, n: int):
self._fib.extend([None for i in range(1 + n - len(self._fib))])
def f(n: int, mem: list):
if n == 0:
mem[n] = 0
return mem
if n == 1:
mem[n] = 1
return mem
else:
if mem[n - 1] is not None:
n1 = mem[n - 1]
else:
n1 = f(n - 1, mem)[n - 1]
if mem[n - 2] is not None:
n2 = mem[n - 2]
else:
n2 = f(n - 2, mem)[n - 2]
mem[n] = n1 + n2
return mem
self._fib = f(n, self._fib)
return self._fib[n]
def encode(self, to_encode: int) -> str:
nums = ["0" for i in range(self._next_fib(to_encode))]
while to_encode > 0:
nf = self._next_fib(to_encode)
to_encode -= self._fibonacci(nf)
nums[nf - 2] = "1"
nums[-1] = "1"
return "".join(nums)
def decode(self, to_decode: str) -> int:
assert (to_decode.isnumeric())
to_decode = to_decode[:len(to_decode) - 1]
ret = 0
for (n, v) in enumerate(to_decode):
factor = int(v)
ret += factor * self._fibonacci(n + 2)
return ret
import unittest
from fib import FibCoder
class TestFibGeneration(unittest.TestCase):
def test_up_to_8(self):
f = FibCoder(seed=8)
assert (f._fib == [0, 1, 1, 2, 3, 5, 8, 13, 21])
class TestClosestFib(unittest.TestCase):
def test_on_the_dot(self):
f = FibCoder(seed=5)
assert (f._next_fib(2) == 3)
def test_need_to_grow(self):
f = FibCoder(seed=2)
assert (f._next_fib(2) == 3)
def test_a_little_ess(self):
f = FibCoder(seed=8)
assert (f._next_fib(14) == 7)
class TestCoding(unittest.TestCase):
cases = [
[1, "11"],
[2, "011"],
[14, "1000011"],
[65, "0100100011"]
]
def test_cases(self):
f = FibCoder()
for case in TestCoding.cases:
assert (f.encode(case[0]) == case[1])
assert (f.decode(case[1]) == case[0])
def test_random(self):
import random
f = FibCoder()
randoms = [random.randint(1, 100) for x in range(100)]
for r in randoms:
assert (f.decode(f.encode(r)) == r)
if __name__ == "__main__":
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment