diff --git a/maths/addition_without_arithmetic.py b/bit_manipulation/addition_without_arithmetic.py similarity index 100% rename from maths/addition_without_arithmetic.py rename to bit_manipulation/addition_without_arithmetic.py diff --git a/maths/binary_exp_mod.py b/maths/binary_exp_mod.py index 67dd1e728b18..ec205383f09c 100644 --- a/maths/binary_exp_mod.py +++ b/maths/binary_exp_mod.py @@ -17,6 +17,74 @@ def bin_exp_mod(a, n, b): return (r * r) % b +def binary_exponentiation_mod_multiplication(a, b, c): + """ + * Binary Exponentiation with Multiplication + * This is a method to find a*b in a time complexity of O(log b) + * This is one of the most commonly used methods of finding result of multiplication. + * Also useful in cases where solution to (a*b)%c is required, + * where a,b,c can be numbers over the computers calculation limits. + * Done using iteration, can also be done using recursion + + * Let's say you need to calculate a ^ b + * RULE 1 : a * b = (a+a) * (b/2) -- example : 4 * 4 = (4+4) * (4/2) = 8 * 2 + * RULE 2 : IF b is ODD, then -- a * b = a + (a * (b - 1)) :: where (b - 1) is even. + * Once b is even, repeat the process to get a * b + * Repeat the process till b = 1 OR b = 0, because a*1 = a AND a*0 = 0 + * + * As far as the modulo is concerned, + * the fact : (a+b) % c = ((a%c) + (b%c)) % c + * Now apply RULE 1 OR 2, whichever is required. + + * @author chinmoy159 + * @version 1.0 dated 10/08/2017 + """ + + res = 0 + while b > 0: + if b & 1: + res = ((res % c) + (a % c)) % c + + a += a + b >>= 1 + + return res + + +def binary_exponentiation_mod_powers(a, b, c): + """ + * Binary Exponentiation for Powers + * This is a method to find a^b in a time complexity of O(log b) + * This is one of the most commonly used methods of finding powers. + * Also useful in cases where solution to (a^b)%c is required, + * where a,b,c can be numbers over the computers calculation limits. + * Done using iteration, can also be done using recursion + + * Let's say you need to calculate a ^ b + * RULE 1 : a ^ b = (a*a) ^ (b/2) -- example : 4 ^ 4 = (4*4) ^ (4/2) = 16 ^ 2 + * RULE 2 : IF b is ODD, then -- a ^ b = a * (a ^ (b - 1)) :: where (b - 1) is even. + * Once b is even, repeat the process to get a ^ b + * Repeat the process till b = 1 OR b = 0, because a^1 = a AND a^0 = 1 + * + * As far as the modulo is concerned, + * the fact : (a*b) % c = ((a%c) * (b%c)) % c + * Now apply RULE 1 OR 2 whichever is required. + + * @author chinmoy159 + * @version 1.0 dated 10/08/2017 + """ + + res = 1 + while b > 0: + if b & 1: + res = ((res % c) * (a % c)) % c + + a *= a + b >>= 1 + + return res + + if __name__ == "__main__": try: BASE = int(input("Enter Base : ").strip()) diff --git a/maths/binary_exponentiation.py b/maths/binary_exponentiation.py index 8dda5245cf44..7e528a9f52f7 100644 --- a/maths/binary_exponentiation.py +++ b/maths/binary_exponentiation.py @@ -1,20 +1,78 @@ -"""Binary Exponentiation.""" +def binary_exponentiation_multiplication(a, b): + """ + * Binary Exponentiation with Multiplication + * This is a method to find a*b in a time complexity of O(log b) + * This is one of the most commonly used methods of finding result of multiplication. + * Also useful in cases where solution to (a*b)%c is required, + * where a,b,c can be numbers over the computers calculation limits. + * Done using iteration, can also be done using recursion -# Author : Junth Basnet -# Time Complexity : O(logn) + * Let's say you need to calculate a * b + * RULE 1 : a * b = (a+a) * (b/2) -- example : 4 * 4 = (4+4) * (4/2) = 8 * 2 + * RULE 2 : IF b is ODD, then -- a * b = a + (a * (b - 1)) :: where (b - 1) is even. + * Once b is even, repeat the process to get a * b + * Repeat the process till b = 1 OR b = 0, because a*1 = a AND a*0 = 0 + * @author chinmoy159 + * @version 1.0 dated 10/08/2017 + """ -def binary_exponentiation(a, n): + res = 0 + while b > 0: + if b & 1: + res += a - if n == 0: + a += a + b >>= 1 + + return res + + +def binary_exponentiation_powers(a, b): + """ + * Binary Exponentiation for Powers + * This is a method to find a^b in a time complexity of O(log b) + * This is one of the most commonly used methods of finding powers. + * Also useful in cases where solution to (a^b)%c is required, + * where a,b,c can be numbers over the computers calculation limits. + * Done using iteration, can also be done using recursion + + * Let's say you need to calculate a ^ b + * RULE 1 : a ^ b = (a*a) ^ (b/2) -- example : 4 ^ 4 = (4*4) ^ (4/2) = 16 ^ 2 + * RULE 2 : IF b is ODD, then -- a ^ b = a * (a ^ (b - 1)) :: where (b - 1) is even. + * Once b is even, repeat the process to get a ^ b + * Repeat the process till b = 1 OR b = 0, because a^1 = a AND a^0 = 1 + + * @author chinmoy159 + * @version 1.0 dated 10/08/2017 + """ + + res = 1 + while b > 0: + if b & 1: + res *= a + + a *= a + b >>= 1 + + return res + + +def binary_exponentiation_recursion(a, b): + """Binary Exponentiation with recursion. + + * Time Complexity : O(logn) + * @author : Junth Basnet + """ + + if b == 0: return 1 - elif n % 2 == 1: - return binary_exponentiation(a, n - 1) * a + elif b % 2 == 1: + return binary_exponentiation_recursion(a, b - 1) * a else: - b = binary_exponentiation(a, n / 2) - return b * b + return binary_exponentiation_recursion(a, b / 2) ** 2 if __name__ == "__main__": @@ -24,5 +82,5 @@ def binary_exponentiation(a, n): except ValueError: print("Invalid literal for integer") - RESULT = binary_exponentiation(BASE, POWER) + RESULT = binary_exponentiation_recursion(BASE, POWER) print(f"{BASE}^({POWER}) : {RESULT}") diff --git a/maths/binary_exponentiation_2.py b/maths/binary_exponentiation_2.py deleted file mode 100644 index 51ec4baf2598..000000000000 --- a/maths/binary_exponentiation_2.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -* Binary Exponentiation with Multiplication -* This is a method to find a*b in a time complexity of O(log b) -* This is one of the most commonly used methods of finding result of multiplication. -* Also useful in cases where solution to (a*b)%c is required, -* where a,b,c can be numbers over the computers calculation limits. -* Done using iteration, can also be done using recursion - -* @author chinmoy159 -* @version 1.0 dated 10/08/2017 -""" - - -def b_expo(a, b): - res = 0 - while b > 0: - if b & 1: - res += a - - a += a - b >>= 1 - - return res - - -def b_expo_mod(a, b, c): - res = 0 - while b > 0: - if b & 1: - res = ((res % c) + (a % c)) % c - - a += a - b >>= 1 - - return res - - -""" -* Wondering how this method works ! -* It's pretty simple. -* Let's say you need to calculate a ^ b -* RULE 1 : a * b = (a+a) * (b/2) ---- example : 4 * 4 = (4+4) * (4/2) = 8 * 2 -* RULE 2 : IF b is ODD, then ---- a * b = a + (a * (b - 1)) :: where (b - 1) is even. -* Once b is even, repeat the process to get a * b -* Repeat the process till b = 1 OR b = 0, because a*1 = a AND a*0 = 0 -* -* As far as the modulo is concerned, -* the fact : (a+b) % c = ((a%c) + (b%c)) % c -* Now apply RULE 1 OR 2, whichever is required. -""" diff --git a/maths/binary_exponentiation_3.py b/maths/binary_exponentiation_3.py deleted file mode 100644 index dd4e70e74129..000000000000 --- a/maths/binary_exponentiation_3.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -* Binary Exponentiation for Powers -* This is a method to find a^b in a time complexity of O(log b) -* This is one of the most commonly used methods of finding powers. -* Also useful in cases where solution to (a^b)%c is required, -* where a,b,c can be numbers over the computers calculation limits. -* Done using iteration, can also be done using recursion - -* @author chinmoy159 -* @version 1.0 dated 10/08/2017 -""" - - -def b_expo(a, b): - res = 1 - while b > 0: - if b & 1: - res *= a - - a *= a - b >>= 1 - - return res - - -def b_expo_mod(a, b, c): - res = 1 - while b > 0: - if b & 1: - res = ((res % c) * (a % c)) % c - - a *= a - b >>= 1 - - return res - - -""" -* Wondering how this method works ! -* It's pretty simple. -* Let's say you need to calculate a ^ b -* RULE 1 : a ^ b = (a*a) ^ (b/2) ---- example : 4 ^ 4 = (4*4) ^ (4/2) = 16 ^ 2 -* RULE 2 : IF b is ODD, then ---- a ^ b = a * (a ^ (b - 1)) :: where (b - 1) is even. -* Once b is even, repeat the process to get a ^ b -* Repeat the process till b = 1 OR b = 0, because a^1 = a AND a^0 = 1 -* -* As far as the modulo is concerned, -* the fact : (a*b) % c = ((a%c) * (b%c)) % c -* Now apply RULE 1 OR 2 whichever is required. -""" diff --git a/maths/double_factorial_iterative.py b/maths/double_factorial_iterative.py deleted file mode 100644 index b2b58aa04c28..000000000000 --- a/maths/double_factorial_iterative.py +++ /dev/null @@ -1,33 +0,0 @@ -def double_factorial(num: int) -> int: - """ - Compute double factorial using iterative method. - - To learn about the theory behind this algorithm: - https://en.wikipedia.org/wiki/Double_factorial - - >>> import math - >>> all(double_factorial(i) == math.prod(range(i, 0, -2)) for i in range(20)) - True - >>> double_factorial(0.1) - Traceback (most recent call last): - ... - ValueError: double_factorial() only accepts integral values - >>> double_factorial(-1) - Traceback (most recent call last): - ... - ValueError: double_factorial() not defined for negative values - """ - if not isinstance(num, int): - raise ValueError("double_factorial() only accepts integral values") - if num < 0: - raise ValueError("double_factorial() not defined for negative values") - value = 1 - for i in range(num, 0, -2): - value *= i - return value - - -if __name__ == "__main__": - import doctest - - doctest.testmod() diff --git a/maths/double_factorial_recursive.py b/maths/double_factorial_recursive.py index 05c9b29680a7..2997c78fb9c7 100644 --- a/maths/double_factorial_recursive.py +++ b/maths/double_factorial_recursive.py @@ -1,4 +1,33 @@ -def double_factorial(n: int) -> int: +def double_factorial(num: int) -> int: + """ + Compute double factorial using iterative method. + + To learn about the theory behind this algorithm: + https://en.wikipedia.org/wiki/Double_factorial + + >>> import math + >>> all(double_factorial(i) == math.prod(range(i, 0, -2)) for i in range(20)) + True + >>> double_factorial(0.1) + Traceback (most recent call last): + ... + ValueError: double_factorial() only accepts integral values + >>> double_factorial(-1) + Traceback (most recent call last): + ... + ValueError: double_factorial() not defined for negative values + """ + if not isinstance(num, int): + raise ValueError("double_factorial() only accepts integral values") + if num < 0: + raise ValueError("double_factorial() not defined for negative values") + value = 1 + for i in range(num, 0, -2): + value *= i + return value + + +def double_factorial_recursive(n: int) -> int: """ Compute double factorial using recursive method. Recursion can be costly for large numbers. @@ -22,7 +51,7 @@ def double_factorial(n: int) -> int: raise ValueError("double_factorial() only accepts integral values") if n < 0: raise ValueError("double_factorial() not defined for negative values") - return 1 if n <= 1 else n * double_factorial(n - 2) + return 1 if n <= 1 else n * double_factorial_recursive(n - 2) if __name__ == "__main__": diff --git a/maths/find_max.py b/maths/find_max.py index 684fbe8161e8..8af8f5e0e334 100644 --- a/maths/find_max.py +++ b/maths/find_max.py @@ -25,6 +25,59 @@ def find_max(nums: list[int | float]) -> int | float: return max_num +# Divide and Conquer algorithm +def find_max_recursive(nums: list[int | float], left: int, right: int) -> int | float: + """ + find max value in list + :param nums: contains elements + :param left: index of first element + :param right: index of last element + :return: max in nums + + >>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]): + ... find_max_recursive(nums, 0, len(nums) - 1) == max(nums) + True + True + True + True + >>> nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] + >>> find_max_recursive(nums, 0, len(nums) - 1) == max(nums) + True + >>> find_max_recursive([], 0, 0) + Traceback (most recent call last): + ... + ValueError: find_max_recursive() arg is an empty sequence + >>> find_max_recursive(nums, 0, len(nums)) == max(nums) + Traceback (most recent call last): + ... + IndexError: list index out of range + >>> find_max_recursive(nums, -len(nums), -1) == max(nums) + True + >>> find_max_recursive(nums, -len(nums) - 1, -1) == max(nums) + Traceback (most recent call last): + ... + IndexError: list index out of range + """ + if len(nums) == 0: + raise ValueError("find_max_recursive() arg is an empty sequence") + if ( + left >= len(nums) + or left < -len(nums) + or right >= len(nums) + or right < -len(nums) + ): + raise IndexError("list index out of range") + if left == right: + return nums[left] + mid = (left + right) // 2 # the middle + left_max = find_max_recursive(nums, left, mid) # find max in range[left, mid] + right_max = find_max_recursive( + nums, mid + 1, right + ) # find max in range[mid + 1, right] + + return left_max if left_max >= right_max else right_max + + if __name__ == "__main__": import doctest diff --git a/maths/find_max_recursion.py b/maths/find_max_recursion.py deleted file mode 100644 index 629932e0818f..000000000000 --- a/maths/find_max_recursion.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - - -# Divide and Conquer algorithm -def find_max(nums: list[int | float], left: int, right: int) -> int | float: - """ - find max value in list - :param nums: contains elements - :param left: index of first element - :param right: index of last element - :return: max in nums - - >>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]): - ... find_max(nums, 0, len(nums) - 1) == max(nums) - True - True - True - True - >>> nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] - >>> find_max(nums, 0, len(nums) - 1) == max(nums) - True - >>> find_max([], 0, 0) - Traceback (most recent call last): - ... - ValueError: find_max() arg is an empty sequence - >>> find_max(nums, 0, len(nums)) == max(nums) - Traceback (most recent call last): - ... - IndexError: list index out of range - >>> find_max(nums, -len(nums), -1) == max(nums) - True - >>> find_max(nums, -len(nums) - 1, -1) == max(nums) - Traceback (most recent call last): - ... - IndexError: list index out of range - """ - if len(nums) == 0: - raise ValueError("find_max() arg is an empty sequence") - if ( - left >= len(nums) - or left < -len(nums) - or right >= len(nums) - or right < -len(nums) - ): - raise IndexError("list index out of range") - if left == right: - return nums[left] - mid = (left + right) >> 1 # the middle - left_max = find_max(nums, left, mid) # find max in range[left, mid] - right_max = find_max(nums, mid + 1, right) # find max in range[mid + 1, right] - - return left_max if left_max >= right_max else right_max - - -if __name__ == "__main__": - import doctest - - doctest.testmod(verbose=True) diff --git a/maths/find_min.py b/maths/find_min.py index 2eac087c6388..1a0959924072 100644 --- a/maths/find_min.py +++ b/maths/find_min.py @@ -28,6 +28,59 @@ def find_min(nums: list[int | float]) -> int | float: return min_num +# Divide and Conquer algorithm +def find_min_recursive(nums: list[int | float], left: int, right: int) -> int | float: + """ + find min value in list + :param nums: contains elements + :param left: index of first element + :param right: index of last element + :return: min in nums + + >>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]): + ... find_min_recursive(nums, 0, len(nums) - 1) == min(nums) + True + True + True + True + >>> nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] + >>> find_min_recursive(nums, 0, len(nums) - 1) == min(nums) + True + >>> find_min_recursive([], 0, 0) + Traceback (most recent call last): + ... + ValueError: find_min_recursive() arg is an empty sequence + >>> find_min_recursive(nums, 0, len(nums)) == min(nums) + Traceback (most recent call last): + ... + IndexError: list index out of range + >>> find_min_recursive(nums, -len(nums), -1) == min(nums) + True + >>> find_min_recursive(nums, -len(nums) - 1, -1) == min(nums) + Traceback (most recent call last): + ... + IndexError: list index out of range + """ + if len(nums) == 0: + raise ValueError("find_min_recursive() arg is an empty sequence") + if ( + left >= len(nums) + or left < -len(nums) + or right >= len(nums) + or right < -len(nums) + ): + raise IndexError("list index out of range") + if left == right: + return nums[left] + mid = (left + right) // 2 # the middle + left_min = find_min_recursive(nums, left, mid) # find min in range[left, mid] + right_min = find_min_recursive( + nums, mid + 1, right + ) # find min in range[mid + 1, right] + + return left_min if left_min <= right_min else right_min + + if __name__ == "__main__": import doctest diff --git a/maths/find_min_recursion.py b/maths/find_min_recursion.py deleted file mode 100644 index 4d11015efcd5..000000000000 --- a/maths/find_min_recursion.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - - -# Divide and Conquer algorithm -def find_min(nums: list[int | float], left: int, right: int) -> int | float: - """ - find min value in list - :param nums: contains elements - :param left: index of first element - :param right: index of last element - :return: min in nums - - >>> for nums in ([3, 2, 1], [-3, -2, -1], [3, -3, 0], [3.0, 3.1, 2.9]): - ... find_min(nums, 0, len(nums) - 1) == min(nums) - True - True - True - True - >>> nums = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10] - >>> find_min(nums, 0, len(nums) - 1) == min(nums) - True - >>> find_min([], 0, 0) - Traceback (most recent call last): - ... - ValueError: find_min() arg is an empty sequence - >>> find_min(nums, 0, len(nums)) == min(nums) - Traceback (most recent call last): - ... - IndexError: list index out of range - >>> find_min(nums, -len(nums), -1) == min(nums) - True - >>> find_min(nums, -len(nums) - 1, -1) == min(nums) - Traceback (most recent call last): - ... - IndexError: list index out of range - """ - if len(nums) == 0: - raise ValueError("find_min() arg is an empty sequence") - if ( - left >= len(nums) - or left < -len(nums) - or right >= len(nums) - or right < -len(nums) - ): - raise IndexError("list index out of range") - if left == right: - return nums[left] - mid = (left + right) >> 1 # the middle - left_min = find_min(nums, left, mid) # find min in range[left, mid] - right_min = find_min(nums, mid + 1, right) # find min in range[mid + 1, right] - - return left_min if left_min <= right_min else right_min - - -if __name__ == "__main__": - import doctest - - doctest.testmod(verbose=True) diff --git a/maths/gamma.py b/maths/gamma.py index d5debc58764b..79c9cf199bc7 100644 --- a/maths/gamma.py +++ b/maths/gamma.py @@ -1,4 +1,11 @@ -import math +""" +Gamma function is a very useful tool in math and physics. +It helps calculating complex integral in a convenient way. +for more info: https://en.wikipedia.org/wiki/Gamma_function +Python's Standard Library gamma() function overflows around gamma(171.624). +""" + +from math import exp, pi, sqrt from numpy import inf from scipy.integrate import quad @@ -39,10 +46,76 @@ def gamma(num: float) -> float: def integrand(x: float, z: float) -> float: - return math.pow(x, z - 1) * math.exp(-x) + return pow(x, z - 1) * exp(-x) + + +def gamma_recursive(num: float) -> float: + """ + Calculates the value of Gamma function of num + where num is either an integer (1, 2, 3..) or a half-integer (0.5, 1.5, 2.5 ...). + Implemented using recursion + Examples: + >>> from math import isclose, gamma as math_gamma + >>> gamma_recursive(0.5) + 1.7724538509055159 + >>> gamma_recursive(2) + 1.0 + >>> gamma_recursive(3.5) + 3.3233509704478426 + >>> gamma_recursive(171.5) + 9.483367566824795e+307 + >>> all(\ + isclose(gamma_recursive(num), math_gamma(num)) for num in (0.5, 2, 3.5, 171.5)) + True + >>> gamma_recursive(0) + Traceback (most recent call last): + ... + ValueError: math domain error + >>> gamma_recursive(-1.1) + Traceback (most recent call last): + ... + ValueError: math domain error + >>> gamma_recursive(-4) + Traceback (most recent call last): + ... + ValueError: math domain error + >>> gamma_recursive(172) + Traceback (most recent call last): + ... + OverflowError: math range error + >>> gamma_recursive(1.1) + Traceback (most recent call last): + ... + NotImplementedError: num must be an integer or a half-integer + """ + if num <= 0: + raise ValueError("math domain error") + if num > 171.5: + raise OverflowError("math range error") + elif num - int(num) not in (0, 0.5): + raise NotImplementedError("num must be an integer or a half-integer") + elif num == 0.5: + return sqrt(pi) + else: + return 1.0 if num == 1 else (num - 1) * gamma_recursive(num - 1) + + +def test_gamma() -> None: + """ + >>> test_gamma() + """ + assert gamma_recursive(0.5) == sqrt(pi) + assert gamma_recursive(1) == 1.0 + assert gamma_recursive(2) == 1.0 if __name__ == "__main__": from doctest import testmod testmod() + + num = 1.0 + while num: + num = float(input("Gamma of: ")) + print(f"gamma({num}) = {gamma(num)}") + print("\nEnter 0 to exit...") diff --git a/maths/gamma_recursive.py b/maths/gamma_recursive.py deleted file mode 100644 index 3d6b8c5e8138..000000000000 --- a/maths/gamma_recursive.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -Gamma function is a very useful tool in math and physics. -It helps calculating complex integral in a convenient way. -for more info: https://en.wikipedia.org/wiki/Gamma_function -Python's Standard Library math.gamma() function overflows around gamma(171.624). -""" -from math import pi, sqrt - - -def gamma(num: float) -> float: - """ - Calculates the value of Gamma function of num - where num is either an integer (1, 2, 3..) or a half-integer (0.5, 1.5, 2.5 ...). - Implemented using recursion - Examples: - >>> from math import isclose, gamma as math_gamma - >>> gamma(0.5) - 1.7724538509055159 - >>> gamma(2) - 1.0 - >>> gamma(3.5) - 3.3233509704478426 - >>> gamma(171.5) - 9.483367566824795e+307 - >>> all(isclose(gamma(num), math_gamma(num)) for num in (0.5, 2, 3.5, 171.5)) - True - >>> gamma(0) - Traceback (most recent call last): - ... - ValueError: math domain error - >>> gamma(-1.1) - Traceback (most recent call last): - ... - ValueError: math domain error - >>> gamma(-4) - Traceback (most recent call last): - ... - ValueError: math domain error - >>> gamma(172) - Traceback (most recent call last): - ... - OverflowError: math range error - >>> gamma(1.1) - Traceback (most recent call last): - ... - NotImplementedError: num must be an integer or a half-integer - """ - if num <= 0: - raise ValueError("math domain error") - if num > 171.5: - raise OverflowError("math range error") - elif num - int(num) not in (0, 0.5): - raise NotImplementedError("num must be an integer or a half-integer") - elif num == 0.5: - return sqrt(pi) - else: - return 1.0 if num == 1 else (num - 1) * gamma(num - 1) - - -def test_gamma() -> None: - """ - >>> test_gamma() - """ - assert gamma(0.5) == sqrt(pi) - assert gamma(1) == 1.0 - assert gamma(2) == 1.0 - - -if __name__ == "__main__": - from doctest import testmod - - testmod() - num = 1.0 - while num: - num = float(input("Gamma of: ")) - print(f"gamma({num}) = {gamma(num)}") - print("\nEnter 0 to exit...")