feat(solutions):新增欧拉项目第25-27题解决方案

📝 docs(solutions):添加Binet公式、循环节和质数生成多项式的数学原理文档
This commit is contained in:
2025-12-24 18:26:10 +08:00
parent accc74ff43
commit 1465d62dbf
5 changed files with 279 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
"""
A unit fraction contains 1in the numerator.
The decimal representation of the unit fractions with denominators 2 to 10 are given:
1/2 = 0.5
1/3 = 0.(3)
1/4 = 0.25
1/5 = 0.2
1/6 = 0.1(6)
1/7 = 0.(142857)
1/8 = 0.125
1/9 = 0.(1)
1/10 = 0.1
Where 0.1(6) means 0.166666..., and has a 1-digit recurring cycle.
It can be seen that 1/7 has a 6-digit recurring cycle.
Find the value of d < 1000 for which 1/d contains the longest recurring cycle in its decimal fraction part.
"""
import random
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.6f} seconds")
return result
return wrapper
def repeating_cycle_fermat(d: int) -> int:
# 移除因子2和5
while d % 2 == 0:
d //= 2
while d % 5 == 0:
d //= 5
if d == 1:
return 0
# 费马小定理对于与10互质的d10^(φ(d)) ≡ 1 mod d
# 循环节长度一定是φ(d)的约数
# 计算欧拉函数φ(d)
phi = d
n = d
# 质因数分解求φ(d)
p = 2
while p * p <= n:
if n % p == 0:
phi -= phi // p
while n % p == 0:
n //= p
p += 1 if p == 2 else 2 # 从2开始然后检查奇数
if n > 1:
phi -= phi // n
# 现在找φ的最小约数k使得10^k ≡ 1 mod d
min_cycle = phi
for k in range(1, int(phi**0.5) + 1):
if phi % k == 0:
if pow(10, k, d) == 1:
return k
other = phi // k
if pow(10, other, d) == 1 and other < min_cycle:
min_cycle = other
return min_cycle
@timer
def main_searchall(n: int) -> None:
max_cycle = 0
max_d = 0
for d in range(1, n):
cycle = repeating_cycle_fermat(d)
if cycle > max_cycle:
max_cycle = cycle
max_d = d
print(f"{max_d} have {max_cycle} digits in its decimal fraction part.")
def is_probable_prime(n: int, trials: int = 20) -> bool:
"""Miller-Rabin素性测试快速判断是否为质数"""
if n < 2:
return False
if n in (2, 3):
return True
if n % 2 == 0:
return False
# 将 n-1 写成 d * 2^s 的形式
d = n - 1
s = 0
while d % 2 == 0:
d //= 2
s += 1
# 测试
for _ in range(trials):
a = random.randrange(2, n - 1)
x = pow(a, d, n)
if x == 1 or x == n - 1:
continue
for _ in range(s - 1):
x = pow(x, 2, n)
if x == n - 1:
break
else:
return False
return True
@timer
def main_by_prime(n: int) -> None:
for d in range(n, 0, -1):
max_cycle = d - 1
max_d = d
cycle = repeating_cycle_fermat(d)
if max_cycle == cycle:
print(f"{max_d} have {max_cycle} digits in its decimal fraction part.")
return None
if __name__ == "__main__":
n = 10000
main_searchall(n)
main_by_prime(n)