如何用循环替代重复声明实现3n+1迭代及平滑3D绘图?
考拉兹猜想迭代可视化解决方案
1. 通用N次迭代实现代码
你之前重复声明a0、a1的方式无法扩展到任意次数迭代,用循环可以轻松解决,同时保证每个点的x(输入值)、y(迭代次数)、z(输出值)一一对应:
def collatz(n): if n % 2 == 0: return n // 2 else: return 3 * n + 1 # 配置参数 max_input = 5000 # 输入值范围1~5000 max_iterations = 20 # 总迭代次数(包含初始状态) x = [] # 输入值 y = [] # 迭代次数 z = [] # 变换后的输出值 # 初始状态:迭代次数y=0,输出值等于输入值 current_vals = list(range(1, max_input + 1)) for val in current_vals: x.append(val) y.append(0) z.append(val) # y=0时不做除法,直接保留初始值 # 迭代生成后续状态 for iteration in range(1, max_iterations): current_vals = [collatz(num) for num in current_vals] for val in current_vals: x.append(val) y.append(iteration) z.append(val / iteration) # 实现类似z=x/y的变换,平衡数值范围
2. 解决大值区域信息不清晰问题
通过将z设置为输出值/迭代次数,可以压缩大输出值的量级,同时放大低迭代次数下的小输出值,让3D曲面的细节更均匀。如果需要用初始输入值而非当前输出值计算z,只需修改迭代部分的逻辑:
# 初始化初始输入值列表 initial_vals = list(range(1, max_input + 1)) current_vals = initial_vals.copy() # 初始状态收集不变 for val in initial_vals: x.append(val) y.append(0) z.append(val) # 迭代部分改为关联初始输入值 for iteration in range(1, max_iterations): current_vals = [collatz(num) for num in current_vals] for idx, val in enumerate(current_vals): x.append(initial_vals[idx]) # x始终为初始输入值 y.append(iteration) z.append(initial_vals[idx] / iteration) # z=初始x/y
3. 3D图平滑处理方法
对于大量离散点,最常用的平滑方式是通过插值生成规则网格后绘制曲面,示例代码如下:
import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import griddata # 将列表转为numpy数组 x_np = np.array(x) y_np = np.array(y) z_np = np.array(z) # 创建规则网格:xi为x轴网格点,yi为y轴网格点 xi = np.linspace(x_np.min(), x_np.max(), 100) # x轴分100份,提升平滑度 yi = np.linspace(y_np.min(), y_np.max(), max_iterations) xi, yi = np.meshgrid(xi, yi) # 插值生成平滑z值网格,method可选:'nearest'(最快)、'linear'(中等)、'cubic'(最平滑) zi = griddata((x_np, y_np), z_np, (xi, yi), method='cubic') # 绘制3D平滑曲面 fig = plt.figure(figsize=(10, 7)) ax = fig.add_subplot(111, projection='3d') surface = ax.plot_surface(xi, yi, zi, cmap='viridis', edgecolor='none') ax.set_xlabel('输入值x') ax.set_ylabel('迭代次数y') ax.set_zlabel('z = 输出值/y') fig.colorbar(surface, shrink=0.5, aspect=5) plt.show()
其他辅助平滑技巧
- 降采样:数据量过大时,可每隔N个点取一个,减少计算压力:
sample_idx = np.arange(0, len(x_np), 5) # 每5个点取一个 x_sampled = x_np[sample_idx] y_sampled = y_np[sample_idx] z_sampled = z_np[sample_idx] - 三角化曲面:无需插值,直接用
plot_trisurf基于离散点生成平滑曲面:ax.plot_trisurf(x_np, y_np, z_np, cmap='viridis', smooth=True)
内容的提问来源于stack exchange,提问作者d4shm1r
相关产品推荐
相关产品推荐

