You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现Jacobi迭代法:返回值异常与NaN问题求助

修复Jacobi迭代Python代码中的NaN问题与返回值异常

我来帮你一步步排查代码里的问题,解决NaN和返回值的异常:

核心问题:迭代不收敛导致NaN

你的代码执行后出现NaN,根本原因是当前的系数矩阵A不满足Jacobi迭代的收敛条件,迭代过程中数值不断发散,最终溢出成NaN。

Jacobi迭代收敛的前提是矩阵A满足以下任一条件:

  • 严格对角占优:每行对角线元素的绝对值 > 该行其他所有元素绝对值之和
  • 对称正定:矩阵A对称且所有特征值为正

我们来核对你的A矩阵:

A = np.array([[10.,7.,8.,7.],[7.,5.,6.,5.],[8.,6.,10.,9.],[7.,5.,9.,10.]])

拿第一行举例:对角线元素是10,其他元素和是7+8+7=22,10 < 22,不满足严格对角占优;再查特征值,用np.linalg.eigvals(A)能看到存在负特征值,说明A也不是对称正定矩阵。这就导致Jacobi迭代越算数值越大,最后超出浮点数范围变成NaN。

另外你的代码还有几个小逻辑问题:

  1. 精确解x_e在循环里重复计算完全没必要,它是固定值,算一次就够了
  2. 赋值语句l=[x,x_e,err,iter]=jacobi(...)不符合Python规范,容易搞混变量引用
  3. 残差计算可以用更简洁高效的方式实现

修正后的完整代码

下面是修复并优化后的代码,还加了收敛性预判断:

import numpy as np
from numpy import linalg as la

def jacobi(A, b, ep, x0, Imax):
    # 构造对角矩阵M,以及分解出E、F
    M = np.diag(np.diag(A))
    # 先检查M是否可逆(对角线不能有0)
    if np.any(np.diag(M) == 0):
        raise ValueError("对角矩阵M不可逆,无法执行Jacobi迭代")
    
    E = (-1)*np.tril(A - M)
    F = (-1)*np.triu(A - M)
    N = E + F
    
    # 计算迭代矩阵的谱半径,提前判断收敛性
    inv_M = np.linalg.inv(M)
    G = inv_M @ N  # Jacobi迭代矩阵
    vp = np.linalg.eigvals(G)
    rho = np.max(np.abs(vp))  # 注意取特征值绝对值的最大值
    
    if rho >= 1:
        print(f"⚠️ 警告:Jacobi迭代矩阵的谱半径为{rho:.4f},大于等于1,迭代可能不收敛")
    
    x = x0.copy()  # 复制初始向量,避免修改原始输入
    x_e = np.linalg.solve(A, b)  # 精确解只计算一次,提升效率
    iter_count = 0
    err = la.norm(x_e - x)
    
    # 优化残差计算,用无穷范数更高效
    while iter_count < Imax and np.linalg.norm(b - A@x, np.inf) > ep:
        iter_count += 1
        x = inv_M @ (N @ x + b)
        err = la.norm(x_e - x)
    
    return x, x_e, err, iter_count

# 参数设置
ep = 1e-6
Imax = 1000
x0 = np.zeros(4)
A = np.array([[10.,7.,8.,7.],[7.,5.,6.,5.],[8.,6.,10.,9.],[7.,5.,9.,10.]])
b = np.array([32.,23.,33.,31.])

# 正确的变量赋值方式
x, x_e, err, iter_count = jacobi(A, b, ep, x0, Imax)
result_list = [x, x_e, err, iter_count]
print(result_list)

关键改进说明

  1. 收敛性预检查:提前计算迭代矩阵的谱半径,若大于等于1直接给出警告,让你直观知道迭代不收敛的原因
  2. 精确解优化:把x_e移到循环外计算,避免重复运算浪费资源
  3. 输入保护:用x0.copy()创建新数组,防止修改传入的初始向量
  4. 规范赋值:拆分错误的赋值语句,避免变量引用混乱
  5. 高效残差计算:用np.linalg.norm(..., np.inf)替代手动计算最大残差,代码更简洁

替代方案:换用收敛的迭代方法

因为你的A矩阵不适合Jacobi迭代,如果你需要得到收敛的结果,可以试试Gauss-Seidel迭代,只需要把迭代公式改成:

x = inv_M @ (E @ x + b - F @ x)

或者直接用scipy库中的现成迭代方法(比如scipy.sparse.linalg.gmres),稳定性和效率都会更高。

内容的提问来源于stack exchange,提问作者Shiraz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 18:32:36