import math import tkinter as tk from tkinter import messagebox, ttk from decimal import Decimal, getcontext import threading # 定义 Chudnovsky 算法计算圆周率的函数 def compute_pi_chudnovsky(iterations, progress_callback): # 设置 Decimal 精度,确保足够的有效数字 getcontext().prec = 250 # 设置更高的精度,确保中间计算的准确性 # 初始化常量 C = Decimal(426880) * Decimal(10005).sqrt() M = Decimal(1) L = Decimal(13591409) X = Decimal(-262537412640768000) # 初始 X K = Decimal(6) S = Decimal(L) total_iterations = iterations for i in range(1, total_iterations + 1): # 从 1 开始迭代 if i % 10 == 0: progress_callback((i / total_iterations) * 100) # 计算 M 和 L M = (K**3 - 16 * K) * M // Decimal(i**3) L += Decimal(545140134) # 计算 S try: S += M * L / X except ZeroDivisionError as e: raise ValueError(f"除零错误在迭代次数: {i}, X: {X}, M: {M}, L: {L}") from e except Exception as e: raise ValueError(f"其他错误在迭代次数: {i}, X: {X}, M: {M}, L: {L}, S: {S}") from e # 更新 X 和 K X *= Decimal(-262537412640768000) K += Decimal(12) pi = C / S return +pi # 返回正数值 # 定义工作线程函数,用于在后台计算圆周率 def worker(iterations, progress_callback, result_callback): try: pi_computed = compute_pi_chudnovsky(iterations, progress_callback) result_callback(pi_computed) except Exception as e: result_callback(None, str(e)) # 定义计算按钮点击事件处理函数 def on_calculate(): try: iterations = int(entry_iterations.get()) if iterations < 1: raise ValueError("迭代次数必须大于0") # 创建进度窗口 progress_window = tk.Toplevel(root) progress_window.title("计算进度") # 初始化进度条变量 progress_var = tk.DoubleVar() # 创建进度条控件 progress = ttk.Progressbar(progress_window, variable=progress_var, maximum=100) progress.pack(pady=20, padx=20, fill='x') # 创建进度标签控件 progress_label = tk.Label(progress_window, text="0%") progress_label.pack(pady=10) def progress_callback(progress): progress_var.set(progress) progress_label.config(text=f"{int(progress)}%") progress_window.update_idletasks() # 定义结果回调函数 def result_callback(pi_computed, error=None): progress_window.destroy() if error: messagebox.showerror("错误", error) else: # 获取数学库中的 π 值(这里使用 Decimal 包装) pi_math = Decimal(str(math.pi)) # 计算误差 difference = abs(pi_computed - pi_math) # 格式化显示计算结果和数学库中的 π 值,并用科学计数法显示误差 pi_computed_str = f"{pi_computed:.200f}".rstrip('0').rstrip('.') pi_math_str = f"{pi_math:.200f}".rstrip('0').rstrip('.') difference_str = f"{difference:.20e}" message = (f"计算得到的π: {pi_computed_str}\n" f"数学库中的π: {pi_math_str}\n" f"差异: {difference_str}") messagebox.showinfo("结果", message) # 创建并启动线程进行计算 thread = threading.Thread(target=worker, args=(iterations, progress_callback, result_callback)) thread.start() except ValueError as e: messagebox.showerror("错误", str(e)) # 创建主窗口 root = tk.Tk() root.title("计算圆周率") # 创建标签和输入框 label_iterations = tk.Label(root, text="迭代次数:") label_iterations.grid(row=0, column=0, padx=10, pady=10) entry_iterations = tk.Entry(root) entry_iterations.grid(row=0, column=1, padx=10, pady=10) # 创建计算按钮 button_calculate = tk.Button(root, text="计算", command=on_calculate) button_calculate.grid(row=1, column=0, columnspan=2, pady=10) # 运行主循环 root.mainloop()