123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- 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()
|