From 4922cafaf8d93c420007da008fcb957b8c868e1b Mon Sep 17 00:00:00 2001 From: TheSuperNoob Date: Wed, 12 Feb 2020 13:28:05 +0100 Subject: [PATCH 1/4] Add Chudnovskys algorithm for calculating many digits of pi --- maths/chudnovsky_algorithm.py | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 maths/chudnovsky_algorithm.py diff --git a/maths/chudnovsky_algorithm.py b/maths/chudnovsky_algorithm.py new file mode 100644 index 000000000000..67e80e2750c3 --- /dev/null +++ b/maths/chudnovsky_algorithm.py @@ -0,0 +1,86 @@ +from decimal import Decimal, getcontext +from math import ceil, factorial + + +def pi(precision: int) -> float: + """ + The Chudnovsky algorithm is a fast method for calculating the digits + of PI, based on Ramanujan’s PI formulae. + + https://en.wikipedia.org/wiki/Chudnovsky_algorithm + + PI = constant_term / ( + (multinomial_term * linear_term) / exponential_term + ) + + where constant_term = 426880 * sqrt(10005) + + The linear_term and the exponential_term can be defined + iteratively as follows: + + L_k+1 = L_k + 545140134 where L_0 = 13591409 + X_k+1 = X_k * -262537412640768000 where X_0 = 1 + + The multinomial_term is defined as follows: + + 6k! / ((3k)! * (k!) ^ 3) + + where k is the k_th iteration. + + This algorithm correctly calculates around 14 digits of PI + per iteration + + >>> pi(10) + '3.14159265' + + >>> pi(100) + '3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706' + + >>> pi('hello') + Traceback (most recent call last): + ... + TypeError: Undefined for non-integers + + >>> pi(-1) + Traceback (most recent call last): + ... + ValueError: Undefined for non-natural numbers + + """ + + if not isinstance(precision, int): + raise TypeError("Undefined for non-integers") + + if precision < 1: + raise ValueError("Undefined for non-natural numbers") + + getcontext().prec = precision + + num_iterations = ceil(precision / 14) + constant_term = 426880 * Decimal(10005).sqrt() + + multinomial_term = 1 + exponential_term = 1 + linear_term = 13591409 + + partial_sum = linear_term + + for k in range(1, num_iterations): + multinomial_term = factorial(6 * k) // (factorial(3 * k) * factorial(k) ** 3) + linear_term += 545140134 + exponential_term *= -262537412640768000 + + partial_sum += Decimal(multinomial_term * linear_term) / exponential_term + + return str(constant_term / partial_sum)[:-1] + + +def main(): + + n = 50 + PI = pi(n) + print(f"The first {n} digits of pi is: {PI}") + + +if __name__ == "__main__": + main() From bb4b212c35a463b7f609090e754cdec8092debd1 Mon Sep 17 00:00:00 2001 From: TheSuperNoob Date: Wed, 12 Feb 2020 13:40:27 +0100 Subject: [PATCH 2/4] Update return value type hint --- maths/chudnovsky_algorithm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maths/chudnovsky_algorithm.py b/maths/chudnovsky_algorithm.py index 67e80e2750c3..6499cca7cf3d 100644 --- a/maths/chudnovsky_algorithm.py +++ b/maths/chudnovsky_algorithm.py @@ -2,7 +2,7 @@ from math import ceil, factorial -def pi(precision: int) -> float: +def pi(precision: int) -> str: """ The Chudnovsky algorithm is a fast method for calculating the digits of PI, based on Ramanujan’s PI formulae. From 9faed7a43369f6489ab4d94dbc0676c4fb332556 Mon Sep 17 00:00:00 2001 From: TheSuperNoob Date: Wed, 12 Feb 2020 13:49:36 +0100 Subject: [PATCH 3/4] Initialize partial sum to be of type Decimal --- maths/chudnovsky_algorithm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maths/chudnovsky_algorithm.py b/maths/chudnovsky_algorithm.py index 6499cca7cf3d..6adf5c1d8f4a 100644 --- a/maths/chudnovsky_algorithm.py +++ b/maths/chudnovsky_algorithm.py @@ -63,7 +63,7 @@ def pi(precision: int) -> str: exponential_term = 1 linear_term = 13591409 - partial_sum = linear_term + partial_sum = Decimal(linear_term) for k in range(1, num_iterations): multinomial_term = factorial(6 * k) // (factorial(3 * k) * factorial(k) ** 3) From d913442952d8aa2849c1e4852df0d9e00c83d2c8 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 12 Feb 2020 15:04:31 +0100 Subject: [PATCH 4/4] Update chudnovsky_algorithm.py --- maths/chudnovsky_algorithm.py | 75 ++++++++++++----------------------- 1 file changed, 25 insertions(+), 50 deletions(-) diff --git a/maths/chudnovsky_algorithm.py b/maths/chudnovsky_algorithm.py index 6adf5c1d8f4a..fb188cd6a3d8 100644 --- a/maths/chudnovsky_algorithm.py +++ b/maths/chudnovsky_algorithm.py @@ -4,83 +4,58 @@ def pi(precision: int) -> str: """ - The Chudnovsky algorithm is a fast method for calculating the digits - of PI, based on Ramanujan’s PI formulae. + The Chudnovsky algorithm is a fast method for calculating the digits of PI, + based on Ramanujan’s PI formulae. - https://en.wikipedia.org/wiki/Chudnovsky_algorithm - - PI = constant_term / ( - (multinomial_term * linear_term) / exponential_term - ) + https://en.wikipedia.org/wiki/Chudnovsky_algorithm + PI = constant_term / ((multinomial_term * linear_term) / exponential_term) where constant_term = 426880 * sqrt(10005) - The linear_term and the exponential_term can be defined - iteratively as follows: - + The linear_term and the exponential_term can be defined iteratively as follows: L_k+1 = L_k + 545140134 where L_0 = 13591409 X_k+1 = X_k * -262537412640768000 where X_0 = 1 - The multinomial_term is defined as follows: - + The multinomial_term is defined as follows: 6k! / ((3k)! * (k!) ^ 3) - - where k is the k_th iteration. - - This algorithm correctly calculates around 14 digits of PI - per iteration - - >>> pi(10) - '3.14159265' - - >>> pi(100) - '3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706' - - >>> pi('hello') - Traceback (most recent call last): - ... - TypeError: Undefined for non-integers - - >>> pi(-1) - Traceback (most recent call last): - ... - ValueError: Undefined for non-natural numbers - + where k is the k_th iteration. + + This algorithm correctly calculates around 14 digits of PI per iteration + + >>> pi(10) + '3.14159265' + >>> pi(100) + '3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706' + >>> pi('hello') + Traceback (most recent call last): + ... + TypeError: Undefined for non-integers + >>> pi(-1) + Traceback (most recent call last): + ... + ValueError: Undefined for non-natural numbers """ if not isinstance(precision, int): raise TypeError("Undefined for non-integers") - - if precision < 1: + elif precision < 1: raise ValueError("Undefined for non-natural numbers") getcontext().prec = precision - num_iterations = ceil(precision / 14) constant_term = 426880 * Decimal(10005).sqrt() - multinomial_term = 1 exponential_term = 1 linear_term = 13591409 - partial_sum = Decimal(linear_term) - for k in range(1, num_iterations): multinomial_term = factorial(6 * k) // (factorial(3 * k) * factorial(k) ** 3) linear_term += 545140134 exponential_term *= -262537412640768000 - partial_sum += Decimal(multinomial_term * linear_term) / exponential_term - return str(constant_term / partial_sum)[:-1] -def main(): - - n = 50 - PI = pi(n) - print(f"The first {n} digits of pi is: {PI}") - - if __name__ == "__main__": - main() + n = 50 + print(f"The first {n} digits of pi is: {pi(n)}")