feat(solutions/0057): 添加欧拉计划第57题连分数平方根解法
包含正算递推实现、约分优化及详细数学推导文档
This commit is contained in:
@@ -1,10 +1,26 @@
|
||||
'''
|
||||
It is possible to show that the square root of two can be expressed as an infinite continued fraction.
|
||||
sqrt{2}=1+frac{1}{2+frac{1}{2+frac{1}{2+...}}}
|
||||
|
||||
By expanding this for the first four iterations, we get:
|
||||
begin{aligned}
|
||||
& 1+frac{1}{2}=frac{3}{2}=1.5 \\
|
||||
& 1+frac{1}{2+frac{1}{2}}=frac{7}{5}=1.4 \\
|
||||
& 1+frac{1}{2+frac{1}{2+frac{1}{2}}}=frac{17}{12}=1.41666... \\
|
||||
& 1+frac{1}{2+frac{1}{2+frac{1}{2+frac{1}{2}}}}=frac{41}{29}=1.41379 ldots
|
||||
end{aligned}
|
||||
|
||||
The next three expansions are 99/70, 239/169, and 577/408, but the eighth expansion, 1393/985,
|
||||
is the first example where the number of digits in the numerator exceeds the number of digits in the denominator.
|
||||
|
||||
In the first one-thousand expansions, how many fractions contain a numerator with more digits than the denominator?
|
||||
'''
|
||||
import time
|
||||
from functools import wraps
|
||||
from typing import Any, Callable, TypeVar
|
||||
|
||||
from math import gcd
|
||||
|
||||
F = TypeVar("F", bound=Callable[..., Any])
|
||||
|
||||
|
||||
@@ -37,4 +53,38 @@ def benchmark(repeat: int = 1) -> Callable[[F], F]:
|
||||
wrapper.total_time = 0.0 # type: ignore[attr-defined]
|
||||
return wrapper # type: ignore[return-value]
|
||||
|
||||
return decorator
|
||||
return decorator
|
||||
|
||||
|
||||
def compute_square_root(n: int = 1000) -> list[tuple[int,int]] :
|
||||
"""
|
||||
Compute the square root of 2 up to n expansions.
|
||||
"""
|
||||
cf = [1] + [2 for _ in range(0, n)]
|
||||
p2, p1 = 0, 1 # p_{-2}, p_{-1}
|
||||
q2, q1 = 1, 0 # q_{-2}, q_{-1}
|
||||
results = []
|
||||
for a in cf:
|
||||
p = a * p1 + p2
|
||||
q = a * q1 + q2
|
||||
p2, p1 = p1, p
|
||||
q2, q1 = q1, q
|
||||
if gc := gcd(p, q) != 1:
|
||||
p //= gc
|
||||
q //= gc
|
||||
results.append((p, q))
|
||||
return results
|
||||
|
||||
@benchmark(20)
|
||||
def main() -> None:
|
||||
results = compute_square_root(1000)
|
||||
count = 0
|
||||
for p, q in results:
|
||||
if len(str(p)) > len(str(q)):
|
||||
count += 1
|
||||
print(f"{count} fractions contain a numerator with more digits than the denominator.")
|
||||
print(f"sqrt{2} = {results[-1][0]/results[-1][1]:.15f}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user