Skip to content

Iterative fibonacci with unittests from slash #882

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 8, 2019
8 changes: 0 additions & 8 deletions Project Euler/Problem 01/sol5.py

This file was deleted.

120 changes: 120 additions & 0 deletions maths/fibonacci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# fibonacci.py
"""
1. Calculates the iterative fibonacci sequence

2. Calculates the fibonacci sequence with a formula
an = [ Phin - (phi)n ]/Sqrt[5]
reference-->Su, Francis E., et al. "Fibonacci Number Formula." Math Fun Facts. <http://www.math.hmc.edu/funfacts>
"""
import math
import functools
import time
from decimal import getcontext, Decimal

getcontext().prec = 100


def timer_decorator(func):
@functools.wraps(func)
def timer_wrapper(*args, **kwargs):
start = time.time()
func(*args, **kwargs)
end = time.time()
if int(end - start) > 0:
print(f'Run time for {func.__name__}: {(end - start):0.2f}s')
else:
print(f'Run time for {func.__name__}: {(end - start)*1000:0.2f}ms')
return func(*args, **kwargs)
return timer_wrapper


# define Python user-defined exceptions
class Error(Exception):
"""Base class for other exceptions"""


class ValueTooLargeError(Error):
"""Raised when the input value is too large"""


class ValueTooSmallError(Error):
"""Raised when the input value is not greater than one"""


class ValueLessThanZero(Error):
"""Raised when the input value is less than zero"""


def _check_number_input(n, min_thresh, max_thresh=None):
"""
:param n: single integer
:type n: int
:param min_thresh: min threshold, single integer
:type min_thresh: int
:param max_thresh: max threshold, single integer
:type max_thresh: int
:return: boolean
"""
try:
if n >= min_thresh and max_thresh is None:
return True
elif min_thresh <= n <= max_thresh:
return True
elif n < 0:
raise ValueLessThanZero
elif n < min_thresh:
raise ValueTooSmallError
elif n > max_thresh:
raise ValueTooLargeError
except ValueLessThanZero:
print("Incorrect Input: number must not be less than 0")
except ValueTooSmallError:
print(f'Incorrect Input: input number must be > {min_thresh} for the recursive calculation')
except ValueTooLargeError:
print(f'Incorrect Input: input number must be < {max_thresh} for the recursive calculation')
return False


@timer_decorator
def fib_iterative(n):
"""
:param n: calculate Fibonacci to the nth integer
:type n:int
:return: Fibonacci sequence as a list
"""
n = int(n)
if _check_number_input(n, 2):
seq_out = [0, 1]
a, b = 0, 1
for _ in range(n-len(seq_out)):
a, b = b, a+b
seq_out.append(b)
return seq_out


@timer_decorator
def fib_formula(n):
"""
:param n: calculate Fibonacci to the nth integer
:type n:int
:return: Fibonacci sequence as a list
"""
seq_out = [0, 1]
n = int(n)
if _check_number_input(n, 2, 1000000):
sqrt = Decimal(math.sqrt(5))
phi_1 = Decimal(1 + sqrt) / Decimal(2)
phi_2 = Decimal(1 - sqrt) / Decimal(2)
for i in range(2, n):
temp_out = ((phi_1**Decimal(i)) - (phi_2**Decimal(i))) * (Decimal(sqrt) ** Decimal(-1))
seq_out.append(int(temp_out))
return seq_out


if __name__ == '__main__':
num = 20
# print(f'{fib_recursive(num)}\n')
# print(f'{fib_iterative(num)}\n')
# print(f'{fib_formula(num)}\n')
fib_iterative(num)
fib_formula(num)
File renamed without changes.
1 change: 1 addition & 0 deletions maths/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .. import fibonacci
34 changes: 34 additions & 0 deletions maths/tests/test_fibonacci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
To run with slash:
1. run pip install slash (may need to install C++ builds from Visual Studio website)
2. In the command prompt navigate to your project folder
3. then type--> slash run -vv -k tags:fibonacci ..
-vv indicates the level of verbosity (how much stuff you want the test to spit out after running)
-k is a way to select the tests you want to run. This becomes much more important in large scale projects.
"""

import slash
from .. import fibonacci

default_fib = [0, 1, 1, 2, 3, 5, 8]


@slash.tag('fibonacci')
@slash.parametrize(('n', 'seq'), [(2, [0, 1]), (3, [0, 1, 1]), (9, [0, 1, 1, 2, 3, 5, 8, 13, 21])])
def test_different_sequence_lengths(n, seq):
"""Test output of varying fibonacci sequence lengths"""
iterative = fibonacci.fib_iterative(n)
formula = fibonacci.fib_formula(n)
assert iterative == seq
assert formula == seq


@slash.tag('fibonacci')
@slash.parametrize('n', [7.3, 7.8, 7.0])
def test_float_input_iterative(n):
"""Test when user enters a float value"""
iterative = fibonacci.fib_iterative(n)
formula = fibonacci.fib_formula(n)
assert iterative == default_fib
assert formula == default_fib

9 changes: 9 additions & 0 deletions project_euler/problem_01/sol6.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
a = 3
result = 0
while a < 1000:
if(a % 3 == 0 or a % 5 == 0):
result += a
elif(a % 15 == 0):
result -= a
a += 1
print(result)