├── .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 | [](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 |
--------------------------------------------------------------------------------