引导deepseek实现一个高效算自然对数的底e的高精度算法 - l1t1/note GitHub Wiki
首个实现已经很高效,但后面理解我的改进有偏差,花了二个提示纠偏
#引导deepseek实现一个高效算自然对数的底e的高精度算法
from decimal import Decimal, getcontext
import sys
sys.set_int_max_str_digits(0)
import math
import time
#请用python写一个计算自然对数的底e的高精度算法
def calculate_e(precision, max_iterations=1000):
"""
高精度计算自然对数的底e
参数:
precision: 所需的小数位数
max_iterations: 最大迭代次数(防止无限循环)
返回:
Decimal类型的e值
"""
# 设置Decimal的精度(比需要的多几位以避免舍入误差)
getcontext().prec = precision + 2
e = Decimal(0)
factorial = Decimal(1)
for n in range(max_iterations):
term = Decimal(1) / factorial
e += term
# 检查收敛性 - 如果新项小于10^(-precision),可以停止
if term < Decimal(10) ** (-precision-1):
break
factorial *= (n + 1)
# 调整精度到所需的小数位数
getcontext().prec = precision
return +e # +操作符应用当前精度
#按照你写的e的泰勒级数展开式,预计算从1到所需精度对应的n!,然后通分,计算分子,然后把分子乘以10的对应次方,然后divmod求整数解,然后点小数点,全过程都用整数运算会不会快一点?用python实现这个思路
def calculate_e_integer(digits):
"""
使用纯整数运算计算e到指定小数位数
参数:
digits: 需要计算的小数位数
返回:
e的字符串表示,包含小数点
"""
# 预计算足够的阶乘项
max_terms = digits * 2 # 安全估计需要的项数
factorials = [1] * (max_terms + 1)
for i in range(1, max_terms + 1):
factorials[i] = factorials[i-1] * i
# 计算通分后的分子总和 (分母为max_factorial)
max_factorial = factorials[max_terms]
numerator = 0
for n in range(max_terms + 1):
numerator += max_factorial // factorials[n]
# 计算整数部分和小数部分
int_part = numerator // max_factorial
remainder = numerator % max_factorial
# 计算小数部分
decimal_digits = []
for _ in range(digits):
remainder *= 10
digit = remainder // max_factorial
decimal_digits.append(str(digit))
remainder = remainder % max_factorial
# 组合结果
return f"{int_part}.{''.join(decimal_digits)}"
#这个版本性能不太高,可能与计算分子用了除法numerator += max_factorial // factorials[n]有关,能否用1+n+n(n-1)+n(n-1)(n-2) +....+n! 的方法算分子?请用python实现
def calculate_e_optimized(digits):
"""
使用优化后的整数运算计算e到指定小数位数
参数:
digits: 需要计算的小数位数
返回:
e的字符串表示,包含小数点
"""
# 动态确定需要的项数 (n)
# 根据泰勒级数余项估计: 1/(n+1)! < 10^(-digits)
n = 1
while True:
# 使用斯特林公式近似估算阶乘
# ln(n!) ≈ n*ln(n) - n + 0.5*ln(2πn)
# 我们想要 (n+1)! > 10^digits
log_fact = (n+1)*math.log(n+1) - (n+1) + 0.5*math.log(2*math.pi*(n+1))
if log_fact > digits * math.log(10):
break
n += 1
# 预计算系数: 1, n, n(n-1), n(n-1)(n-2), ..., n!
coefficients = [1] * (n + 1)
for i in range(1, n + 1):
coefficients[i] = coefficients[i-1] * (n - i + 1)
# 计算分子总和
numerator = 0
for coeff in coefficients:
numerator += coeff
# 计算整数部分和小数部分
int_part = numerator // coefficients[-1] # coefficients[-1] = n!
remainder = numerator % coefficients[-1]
# 计算小数部分
decimal_digits = []
for _ in range(digits):
remainder *= 10
digit = remainder // coefficients[-1]
decimal_digits.append(str(digit))
remainder = remainder % coefficients[-1]
return f"{int_part}.{''.join(decimal_digits)}"
#这个版本比原始Decimal版本快,但计算小数用了很多次除法,能否把分子一次性乘以10的所需位数次方,然后用商再除以这个数(实际上只需要把小数点放在第个2个数字左边)
def calculate_e_fast(digits):
"""
使用优化后的整数运算计算e到指定小数位数
通过一次性乘以10^digits来避免多次除法
参数:
digits: 需要计算的小数位数
返回:
e的字符串表示,包含小数点
"""
# 动态确定需要的项数 (n)
n = 1
while True:
log_fact = (n+1)*math.log(n+1) - (n+1) + 0.5*math.log(2*math.pi*(n+1))
if log_fact > digits * math.log(10):
break
n += 1
# 预计算系数: 1, n, n(n-1), n(n-1)(n-2), ..., n!
coefficients = [1] * (n + 1)
for i in range(1, n + 1):
coefficients[i] = coefficients[i-1] * (n - i + 1)
# 计算分子总和
numerator = 0
for coeff in coefficients:
numerator += coeff
# 一次性乘以10^digits
power = 10 ** digits
scaled_numerator = numerator * power
# 计算整数部分和小数部分
total = scaled_numerator // coefficients[-1] # coefficients[-1] = n!
int_part = total // power
decimal_part = total % power
# 格式化为字符串,确保小数部分有正确的位数(前导零)
return f"{int_part}.{str(decimal_part).zfill(digits)}"
# 测试
if __name__ == "__main__":
import time
digits = 10000 # 计算100位小数
start_time = time.time()
e_value = calculate_e_fast(digits)
elapsed = time.time() - start_time
print(f"e (精确到{digits}位小数):")
print(str(e_value)[:102])
print(f"\n计算耗时: {elapsed:.4f}秒")
digits = 10000 # 计算10000位小数
start_time = time.time()
e_value = calculate_e_optimized(digits)
elapsed = time.time() - start_time
print(f"e (精确到{digits}位小数):")
print(str(e_value)[:102])
print(f"\n计算耗时: {elapsed:.4f}秒")
digits = 1000 # 计算1000位小数
start_time = time.time()
e_value = calculate_e_integer(digits)
elapsed = time.time() - start_time
print(f"e (精确到{digits}位小数):")
print(str(e_value)[:102])
print(f"\n计算耗时: {elapsed:.4f}秒")
precision = 10000
start_time = time.time()
e_value = calculate_e(precision)
elapsed = time.time() - start_time
print(f"e (精确到{precision}位小数):")
print(str(e_value)[:102])
print(f"\n计算耗时: {elapsed:.4f}秒")
"""
e (精确到10000位小数):
2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
计算耗时: 0.0176秒
e (精确到10000位小数):
2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
计算耗时: 0.0680秒
e (精确到1000位小数):
2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
计算耗时: 0.1171秒
e (精确到10000位小数):
2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274
计算耗时: 0.2586秒
"""