Python/maths/pi_generator.py
Maxim Smolskiy a42eb35702
Enable ruff E741 rule (#11370)
* Enable ruff E741 rule

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2024-04-19 21:30:22 +02:00

88 lines
2.3 KiB
Python

def calculate_pi(limit: int) -> str:
"""
https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80
Leibniz Formula for Pi
The Leibniz formula is the special case arctan(1) = pi / 4.
Leibniz's formula converges extremely slowly: it exhibits sublinear convergence.
Convergence (https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80#Convergence)
We cannot try to prove against an interrupted, uncompleted generation.
https://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80#Unusual_behaviour
The errors can in fact be predicted, but those calculations also approach infinity
for accuracy.
Our output will be a string so that we can definitely store all digits.
>>> import math
>>> float(calculate_pi(15)) == math.pi
True
Since we cannot predict errors or interrupt any infinite alternating series
generation since they approach infinity, or interrupt any alternating series, we'll
need math.isclose()
>>> math.isclose(float(calculate_pi(50)), math.pi)
True
>>> math.isclose(float(calculate_pi(100)), math.pi)
True
Since math.pi contains only 16 digits, here are some tests with known values:
>>> calculate_pi(50)
'3.14159265358979323846264338327950288419716939937510'
>>> calculate_pi(80)
'3.14159265358979323846264338327950288419716939937510582097494459230781640628620899'
"""
# Variables used for the iteration process
q = 1
r = 0
t = 1
k = 1
n = 3
m = 3
decimal = limit
counter = 0
result = ""
# We can't compare against anything if we make a generator,
# so we'll stick with plain return logic
while counter != decimal + 1:
if 4 * q + r - t < n * t:
result += str(n)
if counter == 0:
result += "."
if decimal == counter:
break
counter += 1
nr = 10 * (r - n * t)
n = ((10 * (3 * q + r)) // t) - 10 * n
q *= 10
r = nr
else:
nr = (2 * q + r) * m
nn = (q * (7 * k) + 2 + (r * m)) // (t * m)
q *= k
t *= m
m += 2
k += 1
n = nn
r = nr
return result
def main() -> None:
print(f"{calculate_pi(50) = }")
import doctest
doctest.testmod()
if __name__ == "__main__":
main()