初始x值为负数时出现List IndexError的问题排查
问题原因分析
- 区间匹配逻辑错误:原代码用
int(x)获取索引,而Python的int()对负数是向零取整,导致负数区间的x被错误分配到右侧区间(比如x=-1.5会被分到[-1,0]区间,而非正确的[-2,-1]区间)。当x接近Fx最后一个元素且不是整数时,Bi = index + 1会超出列表索引范围,触发IndexError。 - 错误的区间匹配同时导致近似结果失真:用错区间后,后续的插值计算基于错误的已知点,自然会出现结果偏差。
解决方案
1. 修复区间匹配逻辑
替换get_value中获取索引的方式,改为遍历Fx找到x所在的正确区间:
def get_value(self, x: float | int) -> float: # 处理x是已知点的情况 if x in self.Fx: return self.Fy[self.Fx.index(x)] # 找到x所在的区间Ai,满足Fx[Ai] < x < Fx[Ai+1] Ai = None for i in range(len(self.Fx)-1): if self.Fx[i] < x < self.Fx[i+1]: Ai = i break if Ai is None: raise ValueError(f"x={x}超出已知点的范围[{self.Fx[0]}, {self.Fx[-1]}]") Bi = Ai + 1 # 后续计算逻辑保持不变
2. 优化__call__方法的循环(可选,增强鲁棒性)
原循环逻辑在负数场景下可运行,但改为基于起始/结束点计算步数的方式更直观,避免因负数乘法产生的潜在误解:
def __call__(self, density: int): Ex, Ey = [], [] start = self.Fx[0] end = self.Fx[-1] total_steps = int((end - start) * density) for step in range(total_steps + 1): x = start + step / density Ex.append(x) Ey.append(self.get_value(x)) return (Ex, Ey)
完整修正后的代码
class Expand: def __init__(self, fx: list, fy: list, dfy: list): # 校验Fx是否严格递增,避免输入无序导致错误 if not all(fx[i] < fx[i+1] for i in range(len(fx)-1)): raise ValueError("fx必须是严格递增的列表") self.Fx = fx self.Fy = fy self.dFy = dfy def get_value(self, x: float | int) -> float: # 处理x是已知点的情况 if x in self.Fx: return self.Fy[self.Fx.index(x)] # 找到x所在的区间 Ai = None for i in range(len(self.Fx)-1): if self.Fx[i] < x < self.Fx[i+1]: Ai = i break if Ai is None: raise ValueError(f"x={x}超出已知点的范围[{self.Fx[0]}, {self.Fx[-1]}]") Bi = Ai + 1 Ax, Bx = self.Fx[Ai], self.Fx[Bi] Ay, By = self.Fy[Ai], self.Fy[Bi] dAy, dBy = self.dFy[Ai], self.dFy[Bi] if dAy == dBy: Vx = (Ax + Bx)/2 Vy = (Ay + By)/2 else: Vx = (By - Ay + dAy*Ax - dBy*Bx)/(dAy - dBy) Vy = Ay + dAy*(Vx - Ax) denominator = (Ax - Bx)**2 p = (Ax - 2*Vx + Bx)/denominator if p != 0: q = 2*(Ax*Vx - 2*Ax*Bx + Vx*Bx)/denominator x = ((4*p*(x - Ax*Bx*p) + q*q)**0.5 - q)/(2*p) y = (Ay*((Bx - x)**2) + (Ax - x)*(Ax*By - 2*Vy*(Bx - x) - By*x))/((Ax - Bx)**2) return y def __call__(self, density: int): Ex, Ey = [], [] start = self.Fx[0] end = self.Fx[-1] total_steps = int((end - start) * density) for step in range(total_steps + 1): x = start + step / density Ex.append(x) Ey.append(self.get_value(x)) return (Ex, Ey) if __name__ == "__main__": import matplotlib.pyplot as plt fx, fy, dfy = [-3, -2, -1, 0], [1, 1, 2, 6], [-0.577215664902, 0.422784335098, 1.8455686702, 7.53670601059] G = Expand(fx, fy, dfy) gx, gy = G(2) plt.plot(fx, fy, color="b", marker='o', label="已知点") plt.plot(gx, gy, color="r", linestyle='--', label="近似曲线") plt.legend() plt.show()
说明
- 新增Fx严格递增的校验,避免因输入无序导致的逻辑错误。
- 区间匹配改为遍历查找,无论正负区间都能正确定位x所在的相邻已知点。
- 测试代码添加了图例和标记,便于观察近似效果。
内容的提问来源于stack exchange,提问作者M11X00
相关产品推荐
相关产品推荐

