|
@@ -0,0 +1,121 @@
|
|
|
+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()
|