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

Fortran实现QR分解结果异常求助:求无LAPACK的正确代码

不依赖LAPACK的Householder变换实现QR分解(Fortran代码)

以下是基于Householder变换实现QR分解的纯Fortran代码,使用real64高精度类型,无LAPACK依赖:

module qr_mod
    use, intrinsic :: iso_fortran_env, only: real64
    implicit none

contains

    ! 计算Householder变换向量v和系数beta,将向量x变换为平行于单位向量e1
    subroutine householder(x, v, beta)
        real(real64), intent(inout) :: x(:)
        real(real64), intent(out) :: v(:), beta
        real(real64) :: sigma, mu

        sigma = dot_product(x(2:), x(2:))
        if (sigma == 0.0_real64) then
            beta = 0.0_real64
            v = 0.0_real64
            return
        end if

        mu = sqrt(x(1)**2 + sigma)
        ! 选择符号避免数值抵消,提升稳定性
        if (x(1) <= 0.0_real64) then
            x(1) = x(1) - mu
        else
            x(1) = -sigma / (x(1) + mu)
        end if

        v = x / x(1)
        beta = 2.0_real64 * x(1)**2 / (sigma + x(1)**2)
        x(1) = mu  ! 变换后x的第一个元素为mu,其余为0
    end subroutine householder

    ! QR分解:输入矩阵A,输出正交矩阵Q和上三角矩阵R,满足A = Q*R
    subroutine qr_householder(A, Q, R)
        real(real64), intent(inout) :: A(:,:)
        real(real64), intent(out) :: Q(:,:), R(:,:)
        integer :: m, n, k
        real(real64), allocatable :: v(:)
        real(real64) :: beta

        m = size(A, 1)
        n = size(A, 2)
        if (size(Q,1)/=m .or. size(Q,2)/=m) error stop "Q的维度必须与A的行数匹配"
        if (size(R,1)/=m .or. size(R,2)/=n) error stop "R的维度必须与A完全匹配"

        ! 初始化Q为单位矩阵,R为A的副本
        Q = 0.0_real64
        do k = 1, m
            Q(k,k) = 1.0_real64
        end do
        R = A

        allocate(v(m))

        do k = 1, n
            ! 对R的第k列,从第k行开始执行Householder变换
            call householder(R(k:m, k), v(k:m), beta)

            ! 更新R:R = H_k * R,H_k = I - beta*v*v^T
            R(k:m, k+1:n) = R(k:m, k+1:n) - beta * matmul(spread(v(k:m), 2, n - k), &
                                                          spread(v(k:m), 1, n - k)) * R(k:m, k+1:n)

            ! 更新Q:Q = Q * H_k^T(H_k是正交矩阵,H_k^T = H_k)
            Q(:,k:m) = Q(:,k:m) - beta * matmul(Q(:,k:m), spread(v(k:m), 2, m - k + 1)) * transpose(v(k:m))
        end do

        deallocate(v)
    end subroutine qr_householder

end module qr_mod

program test_qr_decomposition
    use qr_mod
    implicit none
    real(real64) :: A(3,3), Q(3,3), R(3,3), recon_A(3,3)
    integer :: i

    ! 测试用3x3矩阵
    A = reshape([1.0_real64, 2.0_real64, 3.0_real64, &
                 4.0_real64, 5.0_real64, 6.0_real64, &
                 7.0_real64, 8.0_real64, 10.0_real64], [3,3])

    print *, "=== 原始矩阵 A ==="
    do i = 1, 3
        print "(3F12.6)", A(i,:)
    end do

    ! 执行QR分解
    call qr_householder(A, Q, R)

    print *, new_line('a')//"=== 正交矩阵 Q ==="
    do i = 1, 3
        print "(3F12.6)", Q(i,:)
    end do

    print *, new_line('a')//"=== 上三角矩阵 R ==="
    do i = 1, 3
        print "(3F12.6)", R(i,:)
    end do

    ! 验证分解正确性:A 应等于 Q*R
    recon_A = matmul(Q, R)
    print *, new_line('a')//"=== 重构矩阵 Q*R ==="
    do i = 1, 3
        print "(3F12.6)", recon_A(i,:)
    end do

    ! 验证Q的正交性:Q^T*Q 应接近单位矩阵
    print *, new_line('a')//"=== Q^T * Q(验证正交性) ==="
    do i = 1, 3
        print "(3F12.6)", matmul(transpose(Q), Q)(i,:)
    end do

end program test_qr_decomposition

关键说明

  • 使用real64类型确保数值计算精度,避免单精度下的累积误差
  • householder子程序通过选择合适的符号处理数值稳定性问题,避免减法抵消
  • 分解过程中逐列构造Householder矩阵,同时更新上三角矩阵R和正交矩阵Q
  • 测试程序包含分解正确性验证和正交性验证,可直接编译运行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:27:44