├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── abs └── abs.py ├── differentiation └── simple_numerical_differentiation.py ├── euclidean └── distance.py ├── factorial ├── factorial.py └── factorial_recursion.py ├── fibonacci ├── fibonacci.py ├── fibonacci_optimal_iteration.py └── fibonacci_optimal_memoization.py ├── gcd ├── gcd.py └── gcd_optimal_euclidean.py ├── lcm ├── lcm.py └── lcm_optimal_euclidean.py ├── prime ├── is_prime.py ├── is_prime_improved.py ├── is_prime_optimal.py ├── next_prime.py └── sieve_of_eratosthenes.py ├── pythagorean_triple └── pythagorean_triple.py └── trigonometric_functions └── trig.py /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled files 2 | *.pyc 3 | __pycache__/ 4 | 5 | # editors & IDEs 6 | .vscode/ 7 | .idea/ 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.6-dev" # 3.6 development branch 4 | # command to run tests 5 | script: 6 | - python3 -m doctest */*.py -v -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 ming 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

FUN MATH

4 | 5 |

6 | 7 | 8 | 9 |

10 | 11 |

12 | Implementations of mathematical functions, formulas and concepts 13 |

14 | 15 |


16 | 17 | It provides the mathematical implementations for various topics which are related to mathematical things such as fibonacci, euclidean, prime numbers and so on. Any mathematical topics or concepts are welcome. If you love the math, join to here with your algorithms and codes! 18 | 19 | This repository does not force for using the specific programming languages, but if you are using the Python, you should use the Python 3.6 to contribute or to run. (you wiil use the only Python 3.6+ in the future) 20 | 21 | A solution can be implemented in three ways: 22 | 23 | - **By definition** solution, a mathematical definition. Good example is the fibonacci series. But the solution by definition of the fibonacci has worst performance 24 | - **Optimal** solution which has better performance than by definition one (or best solution). 25 | - **Creative** solution. This may not be optimal one, but creative or funny way. 26 | 27 | ## Run 28 | 29 | * Python 30 | * `python3 -m doctest / -v` 31 | 32 | ## Implementations 33 | 34 | * [abs](abs) 35 | * [abs.py](abs/abs.py) 36 | * combinations 37 | * decomposition 38 | * [differentiation](differentiation) 39 | * [simple_numerical_differentiation.py](differentiation/simple_numerical_differentiation.py) 40 | * [euclidean](euclidean) 41 | * [distance.py](euclidean/distance.py) 42 | * [factorial](factorial) 43 | * [factorial.py](factorial/factorial.py) 44 | * [factorial_recursion.py](factorial/factorial_recursion.py) 45 | * [fibonacci](fibonacci) 46 | * [fibonacci.py](fibonacci/fibonacci.py) 47 | * [fibonacci_optimal_memoization.py](fibonacci/fibonacci_optimal_memoization.py) 48 | * [fibonacci_optimal_iteration.py](fibonacci/fibonacci_optimal_iteration.py) 49 | * [gcd](gcd) 50 | * [gcd.py](gcd/gcd.py) 51 | * [gcd_optimal_euclidean.py](gcd/gcd_optimal_euclidean.py) 52 | * integral 53 | * [lcm](lcm) 54 | * [lcm.py](lcm/lcm.py) 55 | * [lcm_optimal_euclidean.py](lcm/lcm_optimal_euclidean.py) 56 | * matrix 57 | * multiplication 58 | * multiplication_optimal 59 | * permutations 60 | * [prime](prime) 61 | * [is_prime.py](prime/is_prime.py) 62 | * [is_prime_improved.py](prime/is_prime_improved.py) 63 | * [is_prime_optimal.py](prime/is_prime_optimal.py) 64 | * [next_prime.py](prime/next_prime.py) 65 | * [sieve_of_eratosthenes.py](prime/sieve_of_eratosthenes.py) 66 | * [pythagorean_triple](pythagorean_triple) 67 | * [pythagorean_triple.py](pythagorean_triple/pythagorean_triple.py) 68 | * square_root 69 | * [trigonometric_functions](trigonometric_functions) 70 | * [trig.py](trigonometric_functions/trig.py) 71 | 72 | ## Contribution 73 | 74 | * You can implement any sort of algorithms for mathematical things. 75 | * If you add new kind of algorithms, please also add that in README as new category. 76 | * If you want to add other programming language version of existing solutions, you must name the source code file as same to existing one. 77 | * It is better to provide the explains of your algorithms in comments of source code files. 78 | * You can use any programming languages you are preferring, but you **SHOULD** take care of handling large numbers. And if you want to contribute the algorithms with Python, you **SHOULD** write the scripts with Python 3.6+. 79 | * You **MUST** have to write the test codes for each algorithms. See the [example](fibonacci/fibonacci_optimal_memoization.py) for writing the tests (the example is written in Python) 80 | * It is not recommended to use the builtin math libraries as possible. Because this repository encourages that implement the mathematical things by ourselves. 81 | * It is better to provide the optimal solutions as well for each algorithms. 82 | 83 | ## Changelog 84 | > **Enhancement** 85 | > - Link the Travis CI to run the tests when commits [#4](../../issues/4) 86 | > 87 | > **Fixed** 88 | > - Don't check the weird invalid type on functions which accept only specific types [#3](../../issues/3) 89 | > - Remove the stricted type checking on some functions [#2](../../issues/2) 90 | 91 | ## Contributors 92 | 93 | - [@mingrammer](https://github.com/mingrammer) 94 | - [@Xaltonon](https://github.com/Xaltonon ) 95 | - [@TsimpDim](https://github.com/TsimpDim) 96 | 97 | ## License 98 | 99 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmingrammer%2Ffunmath.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmingrammer%2Ffunmath?ref=badge_large) 100 | -------------------------------------------------------------------------------- /abs/abs.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def abs(x): 5 | """Return the absolute value of x, a numeric value 6 | 7 | >>> abs(3) 8 | 3 9 | >>> abs(-10) 10 | 10 11 | >>> abs(0) 12 | 0 13 | >>> abs(-3.14) 14 | 3.14 15 | >>> abs(-3 + 4j) 16 | 5.0 17 | """ 18 | if isinstance(x, complex): 19 | return math.sqrt(x.real ** 2 + x.imag ** 2) 20 | return x if x >= 0 else -x 21 | -------------------------------------------------------------------------------- /differentiation/simple_numerical_differentiation.py: -------------------------------------------------------------------------------- 1 | from typing import Callable 2 | 3 | 4 | def simple_numerical_differentiation(f: Callable[[float], float], x: float) -> float: 5 | """Calculate the differential value for given point(x) on given function(f) 6 | 7 | By definition, the differential value of a function is defined as follow: 8 | diff = [lim h go to 0] (f(x + h) - f(x - h)) / 2h 9 | 10 | # f(x) = 2x 11 | >>> abs(simple_numerical_differentiation(lambda x: 2*x, 3) - 2) < 1e-06 12 | True 13 | 14 | # f(x) = 3x^3 - 2x^2 + x - 3 15 | >>> abs(simple_numerical_differentiation(lambda x: 3*x**3 - 2*x**2 + x - 3, 1) - 6) < 1e-06 16 | True 17 | """ 18 | h = 1e-4 19 | diff = (f(x + h) - f(x - h)) / (2 * h) 20 | return diff 21 | -------------------------------------------------------------------------------- /euclidean/distance.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numbers 3 | from typing import Tuple 4 | 5 | 6 | def euclidean_distance(p1: Tuple[numbers.Integral, numbers.Integral], 7 | p2: Tuple[numbers.Integral, numbers.Integral]) -> numbers.Integral: 8 | """Calculate the distance between two points on coordinate plane 9 | 10 | >>> euclidean_distance((0, 0), (3, 4)) 11 | 5.0 12 | >>> euclidean_distance((-1, 3), (7, 9)) 13 | 10.0 14 | """ 15 | x1, y1 = p1 16 | x2, y2 = p2 17 | dx = x1 - x2 18 | dy = y1 - y2 19 | return math.sqrt(dx ** 2 + dy ** 2) 20 | -------------------------------------------------------------------------------- /factorial/factorial.py: -------------------------------------------------------------------------------- 1 | def factorial(n: int) -> int: 2 | """Return the factorial of n, an exact integer >= 0 3 | 4 | >>> factorial(4) 5 | 24 6 | >>> factorial(10) 7 | 3628800 8 | >>> factorial(25) 9 | 15511210043330985984000000 10 | >>> factorial(-2) 11 | Traceback (most recent call last): 12 | ... 13 | ValueError: n must be >= 0 14 | """ 15 | if n < 0: 16 | raise ValueError("n must be >= 0") 17 | result = 1 18 | factor = 2 19 | while factor <= n: 20 | result *= factor 21 | factor += 1 22 | return result 23 | -------------------------------------------------------------------------------- /factorial/factorial_recursion.py: -------------------------------------------------------------------------------- 1 | def factorial(n: int) -> int: 2 | """Return the factorial of n, an exact integer >= 0 3 | 4 | By definition, the factorial is defined as follow: 5 | factorial(n) = n * factorial(n - 1), factorial(0) = factorial(1) = 1 6 | 7 | >>> factorial(4) 8 | 24 9 | >>> factorial(10) 10 | 3628800 11 | >>> factorial(25) 12 | 15511210043330985984000000 13 | >>> factorial(-2) 14 | Traceback (most recent call last): 15 | ... 16 | ValueError: n must be >= 0 17 | """ 18 | if n < 0: 19 | raise ValueError("n must be >= 0") 20 | if n <= 1: 21 | return 1 22 | return n * factorial(n - 1) 23 | -------------------------------------------------------------------------------- /fibonacci/fibonacci.py: -------------------------------------------------------------------------------- 1 | def fibonacci(n: int) -> int: 2 | """Return the nth fibonacci number 3 | 4 | >>> fibonacci(0) 5 | 0 6 | >>> fibonacci(1) 7 | 1 8 | >>> fibonacci(10) 9 | 55 10 | >>> fibonacci(20) 11 | 6765 12 | >>> fibonacci(-2) 13 | Traceback (most recent call last): 14 | ... 15 | ValueError: n must be >= 0 16 | """ 17 | if n < 0: 18 | raise ValueError("n must be >= 0") 19 | if n < 2: 20 | return n 21 | return fibonacci(n - 1) + fibonacci(n - 2) 22 | -------------------------------------------------------------------------------- /fibonacci/fibonacci_optimal_iteration.py: -------------------------------------------------------------------------------- 1 | def fibonacci_optimal_iteration(n: int) -> int: 2 | """Return the nth fibonacci number using optimal iteration method 3 | 4 | This function calculate a fibonacci number using iteration loop, not recursion. 5 | So it has O(n) time complexity which is very fast. 6 | 7 | >>> fibonacci_optimal_iteration(0) 8 | 0 9 | >>> fibonacci_optimal_iteration(1) 10 | 1 11 | >>> fibonacci_optimal_iteration(50) 12 | 12586269025 13 | >>> fibonacci_optimal_iteration(200) 14 | 280571172992510140037611932413038677189525 15 | >>> fibonacci_optimal_iteration(-2) 16 | Traceback (most recent call last): 17 | ... 18 | ValueError: n must be >= 0 19 | """ 20 | if n < 0: 21 | raise ValueError("n must be >= 0") 22 | a, b = 0, 1 23 | for _ in range(1, n + 1): 24 | a, b = b, a + b 25 | return a 26 | -------------------------------------------------------------------------------- /fibonacci/fibonacci_optimal_memoization.py: -------------------------------------------------------------------------------- 1 | fibo_dict = { 2 | 0: 0, 3 | 1: 1, 4 | } 5 | 6 | 7 | def fibonacci_optimal_memoization(n: int) -> int: 8 | """Return the nth fibonacci number using optimal memoization method 9 | 10 | This function uses fibonacci dict for caching the calculated fibonacci numbers. 11 | So it does not recalculate the every fibonacci number, so this would be very fast. 12 | 13 | >>> fibonacci_optimal_memoization(0) 14 | 0 15 | >>> fibonacci_optimal_memoization(1) 16 | 1 17 | >>> fibonacci_optimal_memoization(50) 18 | 12586269025 19 | >>> fibonacci_optimal_memoization(200) 20 | 280571172992510140037611932413038677189525 21 | >>> fibonacci_optimal_memoization(-2) 22 | Traceback (most recent call last): 23 | ... 24 | ValueError: n must be >= 0 25 | """ 26 | if n < 0: 27 | raise ValueError("n must be >= 0") 28 | if n in fibo_dict: 29 | return fibo_dict[n] 30 | else: 31 | fibo_dict[n] = fibonacci_optimal_memoization(n - 1) + fibonacci_optimal_memoization(n - 2) 32 | return fibo_dict[n] 33 | -------------------------------------------------------------------------------- /gcd/gcd.py: -------------------------------------------------------------------------------- 1 | def gcd(a: int, b: int) -> int: 2 | """Return a GCD (Greatest Common Divisor) of given two integers 3 | 4 | >>> gcd(1, 10) 5 | 1 6 | >>> gcd(45, 81) 7 | 9 8 | >>> gcd(63, 130) 9 | 1 10 | >>> gcd(-20, 30) 11 | 10 12 | """ 13 | g = min(abs(a), abs(b)) 14 | while g >= 1: 15 | if a % g == 0 and b % g == 0: 16 | return g 17 | g -= 1 18 | -------------------------------------------------------------------------------- /gcd/gcd_optimal_euclidean.py: -------------------------------------------------------------------------------- 1 | def gcd_optimal_euclidean(a: int, b: int) -> int: 2 | """Return a GCD (Greatest Common Divisor) of given two integers using euclidean algorithm 3 | 4 | This function uses euclidean algorithm to get GCD of two integers. 5 | This algorithm works as follows. 6 | 7 | gcd(100, 36) 8 | = gcd(36, 28 (= 100 mod 36)) 9 | = gcd(28, 8 (= 36 mod 28)) 10 | = gcd(8, 4 (= 28 mod 8)) 11 | = gcd(4, 0 (= 8 mod 4)) 12 | = 4 (do until smaller one being 0, so then the other becomes GCD) 13 | 14 | >>> gcd_optimal_euclidean(1, 10) 15 | 1 16 | >>> gcd_optimal_euclidean(45, 81) 17 | 9 18 | >>> gcd_optimal_euclidean(1111, 10000000000001) 19 | 11 20 | >>> gcd_optimal_euclidean(-20, 30) 21 | 10 22 | """ 23 | if b == 0: 24 | return a 25 | a, b = b, a % b 26 | return gcd_optimal_euclidean(a, b) 27 | -------------------------------------------------------------------------------- /lcm/lcm.py: -------------------------------------------------------------------------------- 1 | def lcm(a: int, b: int) -> int: 2 | """Return a LCM (Lowest Common Multiple) of given two integers 3 | 4 | >>> lcm(3, 10) 5 | 30 6 | >>> lcm(42, 63) 7 | 126 8 | >>> lcm(40, 80) 9 | 80 10 | >>> lcm(-20, 30) 11 | 60 12 | """ 13 | g = min(abs(a), abs(b)) 14 | while g >= 1: 15 | if a % g == 0 and b % g == 0: 16 | break 17 | g -= 1 18 | return abs(int((a * b) / g)) 19 | -------------------------------------------------------------------------------- /lcm/lcm_optimal_euclidean.py: -------------------------------------------------------------------------------- 1 | def gcd_optimal_euclidean(a: int, b: int) -> int: 2 | if b == 0: 3 | return a 4 | a, b = b, a % b 5 | return gcd_optimal_euclidean(a, b) 6 | 7 | 8 | def lcm_optimal_euclidean(a: int, b: int) -> int: 9 | """Return a LCM (Lowest Common Multiple) of given two integers using euclidean algorithm 10 | 11 | This function uses euclidean algorithm to get LCM of two integers. 12 | The LCM can be obtained by (a * b) / gcd(a, b), so we can use euclidean algorithm to get LCM by (a * b) / GCD. 13 | This algorithm works as follows. 14 | 15 | gcd(100, 36) 16 | = gcd(36, 28 (= 100 mod 36)) 17 | = gcd(28, 8 (= 36 mod 28)) 18 | = gcd(8, 4 (= 28 mod 8)) 19 | = gcd(4, 0 (= 8 mod 4)) 20 | = 4 (do until smaller one being 0, so then the other becomes GCD) 21 | 22 | So, the LCM will be (100 * 36) / 4 equals 900. 23 | 24 | >>> lcm_optimal_euclidean(3, 10) 25 | 30 26 | >>> lcm_optimal_euclidean(42, 63) 27 | 126 28 | >>> lcm_optimal_euclidean(4041, 8012) 29 | 32376492 30 | >>> lcm_optimal_euclidean(-20, 30) 31 | 60 32 | """ 33 | gcd = gcd_optimal_euclidean(a, b) 34 | return abs(int((a * b) / gcd)) 35 | -------------------------------------------------------------------------------- /prime/is_prime.py: -------------------------------------------------------------------------------- 1 | def is_prime(n: int) -> bool: 2 | """Decide the whether the given integer is prime number or not 3 | 4 | >>> is_prime(1) 5 | False 6 | >>> is_prime(2) 7 | True 8 | >>> is_prime(119) 9 | False 10 | >>> is_prime(977) 11 | True 12 | >>> is_prime(-37) 13 | Traceback (most recent call last): 14 | ... 15 | ValueError: n must be >= 1 16 | """ 17 | if n < 1: 18 | raise ValueError("n must be >= 1") 19 | if n == 1: 20 | return False 21 | for i in range(2, n): 22 | if n % i == 0: 23 | return False 24 | return True 25 | -------------------------------------------------------------------------------- /prime/is_prime_improved.py: -------------------------------------------------------------------------------- 1 | from math import sqrt 2 | 3 | 4 | def is_prime_improved(n: int) -> bool: 5 | """Decide the whether the given integer is prime number or not 6 | 7 | >>> is_prime_improved(1) 8 | False 9 | >>> is_prime_improved(2) 10 | True 11 | >>> is_prime_improved(119) 12 | False 13 | >>> is_prime_improved(977) 14 | True 15 | >>> is_prime_improved(-37) 16 | Traceback (most recent call last): 17 | ... 18 | ValueError: n must be >= 1 19 | """ 20 | if n < 1: 21 | raise ValueError("n must be >= 1") 22 | if n == 1: 23 | return False 24 | if n in (2, 3, 5): 25 | return True 26 | for i in range(6, int(sqrt(n)), 6): 27 | if n % (i - 1) == 0: 28 | return False 29 | if n % (i + 1) == 0: 30 | return False 31 | return True 32 | -------------------------------------------------------------------------------- /prime/is_prime_optimal.py: -------------------------------------------------------------------------------- 1 | import math 2 | import random 3 | 4 | RABIN_MILLER_ROUNDS = 64 # 2^-128 chance of a false positive 5 | 6 | 7 | class ContinueOut(Exception): 8 | pass 9 | 10 | 11 | def is_prime_optimal(n: int) -> bool: 12 | """Decide the whether the given integer is prime number or not more efficiently 13 | 14 | >>> is_prime_optimal(1) 15 | False 16 | >>> is_prime_optimal(2) 17 | True 18 | >>> is_prime_optimal(877) 19 | True 20 | >>> is_prime_optimal(10003002003) 21 | False 22 | >>> is_prime_optimal(32416190071) 23 | True 24 | >>> is_prime_optimal(-37) 25 | Traceback (most recent call last): 26 | ... 27 | ValueError: n must be >= 1 28 | """ 29 | if n < 1: 30 | raise ValueError("n must be >= 1") 31 | if math.floor(n) != n: 32 | raise ValueError("n must be exact integer") 33 | 34 | if n == 1: 35 | return False 36 | elif n in [2, 3, 5]: # special case where n==2, 3 or 5 37 | return True 38 | elif n % 2 == 0: # even number 39 | return False 40 | 41 | d, r = divmod(n - 1, 2) # factor out 2s from n-1 42 | s = 1 43 | while r == 0: 44 | s += 1 45 | d, r = divmod(d, 2) 46 | d = d * 2 + r 47 | s -= 1 48 | 49 | for _ in range(RABIN_MILLER_ROUNDS): 50 | a = random.randint(2, n - 2) 51 | x = pow(a, d, n) 52 | if x == 1 or x == n - 1: 53 | continue 54 | try: 55 | for _ in range(s - 1): 56 | x = pow(x, 2, n) 57 | if x == 1: 58 | return False 59 | if x == n - 1: 60 | raise ContinueOut() 61 | except ContinueOut: 62 | continue 63 | return False 64 | return True 65 | -------------------------------------------------------------------------------- /prime/next_prime.py: -------------------------------------------------------------------------------- 1 | def next_prime(n: int) -> int: 2 | """Find the next prime after the input 3 | 4 | >>> next_prime(3) 5 | 5 6 | >>> next_prime(1421) 7 | 1423 8 | >>> next_prime(-26) 9 | Traceback (most recent call last): 10 | ... 11 | ValueError: n must be >= 1 12 | >>> next_prime(80023045) 13 | 80023051 14 | """ 15 | if n <= 0: 16 | raise ValueError("n must be >= 1") 17 | n += 1 18 | for p in range(n, 2 * n): 19 | for i in range(2, p): 20 | if p % i == 0: 21 | break 22 | else: 23 | return p 24 | -------------------------------------------------------------------------------- /prime/sieve_of_eratosthenes.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | 4 | def sieve_of_eratosthenes(n: int) -> List[int]: 5 | """Return a list of prime numbers which are less than the given integer using sieve of eratosthenes method 6 | 7 | >>> sieve_of_eratosthenes(1) 8 | [] 9 | >>> sieve_of_eratosthenes(10) 10 | [2, 3, 5, 7] 11 | >>> sieve_of_eratosthenes(50) 12 | [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] 13 | >>> sieve_of_eratosthenes(-37) 14 | Traceback (most recent call last): 15 | ... 16 | ValueError: n must be >= 1 17 | """ 18 | if n < 1: 19 | raise ValueError("n must be >= 1") 20 | sieve = [True] * n 21 | sieve[0] = False 22 | for i in range(2, n + 1): 23 | if sieve[i - 1]: 24 | for j in range(i ** 2, n + 1, i): 25 | sieve[j - 1] = False 26 | prime_list = [] 27 | for i, is_prime in enumerate(sieve): 28 | if is_prime: 29 | prime_list.append(i + 1) 30 | return prime_list 31 | -------------------------------------------------------------------------------- /pythagorean_triple/pythagorean_triple.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from typing import Tuple 3 | 4 | 5 | def pythagorean_triple(n: int) -> List[Tuple[int, int, int]]: 6 | """Find all pythagorean triple satisfying the following equation 7 | 8 | a^2 + b^2 = c^2 (1 <= a <= b <= c and a, b, c are natural numbers) 9 | 10 | (above 'c' is same to given 'n' parameter) 11 | 12 | There can be many different solutions such as (3, 4, 5), (5, 12, 13) and so on 13 | 14 | >>> pythagorean_triple(5) 15 | [(3, 4, 5)] 16 | >>> pythagorean_triple(14) 17 | [(3, 4, 5), (5, 12, 13), (6, 8, 10)] 18 | >>> pythagorean_triple(26) 19 | [(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12, 15), (10, 24, 26), (12, 16, 20), (15, 20, 25)] 20 | >>> pythagorean_triple(1) 21 | Traceback (most recent call last): 22 | ... 23 | ValueError: n must be >= 2 24 | """ 25 | if n < 2: 26 | raise ValueError('n must be >= 2') 27 | triple = [(a, b, c) for a in range(1, n + 1) for b in range(a, n + 1) for c in range(b, n + 1) if 28 | a ** 2 + b ** 2 == c ** 2] 29 | return triple 30 | -------------------------------------------------------------------------------- /trigonometric_functions/trig.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | MACLAURIN_SERIES_TERMS = 20 4 | 5 | 6 | def sin(x): 7 | """Returns the sine of x (in radians) 8 | 9 | This uses the Maclaurin expansion of sine to compute sines for the 10 | first quadrant of the unit circle. Anything outsides of the range 11 | [0,π/2] is calculated by exploiting the symmetry of sine. 12 | 13 | >>> abs(sin(0)) < 1e-6 14 | True 15 | >>> abs(sin(math.pi/2) - 1) < 1e-6 16 | True 17 | >>> abs(sin(math.pi*3/2) - (-1)) < 1e-6 18 | True 19 | >>> abs(sin(math.pi*100)) < 1e-6 20 | True 21 | >>> abs(sin(math.pi/4) - 1/2**0.5) < 1e-6 22 | True 23 | >>> abs(sin(math.pi/3) - sin(math.pi/3*2)) < 1e-6 24 | True 25 | """ 26 | 27 | def sin_quadrant(x): 28 | s = 0 29 | sign = 1 30 | for i in range(1, MACLAURIN_SERIES_TERMS, 2): 31 | s += (x ** i) / math.factorial(i) * sign 32 | sign *= -1 33 | return s 34 | 35 | quad = quadrant(x) 36 | norm = x % (math.pi / 2) 37 | if quad == 1: 38 | return sin_quadrant(norm) 39 | elif quad == 2: 40 | return sin_quadrant(math.pi / 2 - norm) 41 | elif quad == 3: 42 | return -sin_quadrant(norm) 43 | elif quad == 4: 44 | return -sin_quadrant(math.pi / 2 - norm) 45 | 46 | 47 | def cos(x): 48 | """Returns the cosine of x (in radians) 49 | 50 | This uses the identity cos(θ) = sin(θ+π/2) 51 | 52 | >>> abs(cos(0) - 1) < 1e-6 53 | True 54 | >>> abs(cos(math.pi) - (-1)) < 1e-6 55 | True 56 | >>> abs(cos(math.pi*3/2)) < 1e-6 57 | True 58 | >>> abs(cos(math.pi*100) - 1) < 1e-6 59 | True 60 | >>> abs(cos(math.pi/4) - sin(math.pi/4)) < 1e-6 61 | True 62 | """ 63 | return sin(x + math.pi / 2) 64 | 65 | 66 | def tan(x): 67 | """Returns the tangent of x (in radians) 68 | 69 | This uses the identity tan(θ) = sin(θ)/cos(θ) 70 | 71 | >>> abs(tan(1) - sin(1)/cos(1)) < 1e-6 72 | True 73 | >>> abs(tan(math.pi*100)) < 1e-6 74 | True 75 | """ 76 | return sin(x) / cos(x) 77 | 78 | 79 | def quadrant(x): 80 | """Returns which quadrant of the unit circle x is in. 81 | """ 82 | norm = x % (math.pi * 2) 83 | quad = x % (math.pi / 2) 84 | if 0 <= norm < math.pi / 2: # first quadrant 85 | return 1 86 | elif math.pi / 2 <= norm < math.pi: # second quadrant 87 | return 2 88 | elif math.pi <= norm < math.pi * (3 / 2): # third quadrant 89 | return 3 90 | elif math.pi * (3 / 2) <= norm < math.pi * 2: # fourth quadrant 91 | return 4 92 | --------------------------------------------------------------------------------