在 Fortran 应用程序中接收 NaN 值

发布于 2024-12-21 17:29:52 字数 2493 浏览 2 评论 0原文

我正在开发一个 Fortran 应用程序,用于数值求解类型为 -y''+q(x)*y=r(x) 的二阶 ODE 的边界值问题。在此应用程序中,我使用高斯消元算法来求解线性方程组并将解写入文件中。但对于解向量我收到 NaN。为什么会这样呢?这是一些代码。

      subroutine gaussian_solve(s, c, error)

    double precision, dimension(:,:), intent(in out) :: s
    double precision, dimension(:),   intent(in out) :: c
         integer        :: error

    if(error == 0) then
        call back_substitution(s, c)
    end if

     end subroutine gaussian_solve
!=========================================================================================

!================= Subroutine gaussian_ellimination ===============================
      subroutine gaussion_ellimination(s, c, error)

    double precision, dimension(:,:), intent(in out) :: s
    double precision, dimension(:),   intent(in out) :: c
    integer,            intent(out)  :: error

    real, dimension(size(s, 1)) :: temp_array
    integer, dimension(1)       :: ksave
    integer                     :: i, j, k, n
    real                        :: temp, m

    n = size(s, 1)

    if(n == 0) then
        error = -1 
        return
    end if

    if(n /= size(s, 2)) then
        error = -2 
        return
    end if

    if(n /= size(s, 2)) then 
        error = -3 
        return
    end if

    error = 0
    do i = 1, n-1
        ksave = maxloc(abs(s(i:n, i)))
        k = ksave(1) + i - 1
        if(s(k, i) == 0) then
            error = -4
            return
        end if

        if(k /= i) then
            temp_array = s(i, :)
            s(i, :) = s(k, :)
            s(k, :) = temp_array
            temp = c(i)
            c(i) = c(k)
            c(k) = temp
        end if

        do j = i + 1, n
            m = s(j, i)/s(i, i)
            s(j, :) = s(j, :) - m*s(i, :)
            c(j) = c(j) - m*c(i)
        end do
    end do

     end subroutine gaussion_ellimination
     !==========================================================================================

   !================= Subroutine back_substitution ========================================
     subroutine back_substitution(s, c)

    double precision, dimension(:,:), intent(in) :: s
    double precision, dimension(:),   intent(in out) :: c

    real    :: w
    integer :: i, j, n

    n = size(c)

    do i = n, 1, -1
        w = c(i)
        do j = i + 1, n
            w = w - s(i, j)*c(j)
        end do
        c(i) = w/s(i, i)
    end do

      end subroutine back_substitution

其中 s(i, j) 是系统系数矩阵,c(i) 是解向量。

I'm developing an Fortran application for numerically solving Boundary Value Problem for second order ODE of the type: -y''+q(x)*y=r(x). In this application I use Gauss-ellimination algorithm to solve the linear system of equations and write the solution in file. But for the solution vector I receive NaN. Why is that happen? Here is some code.

      subroutine gaussian_solve(s, c, error)

    double precision, dimension(:,:), intent(in out) :: s
    double precision, dimension(:),   intent(in out) :: c
         integer        :: error

    if(error == 0) then
        call back_substitution(s, c)
    end if

     end subroutine gaussian_solve
!=========================================================================================

!================= Subroutine gaussian_ellimination ===============================
      subroutine gaussion_ellimination(s, c, error)

    double precision, dimension(:,:), intent(in out) :: s
    double precision, dimension(:),   intent(in out) :: c
    integer,            intent(out)  :: error

    real, dimension(size(s, 1)) :: temp_array
    integer, dimension(1)       :: ksave
    integer                     :: i, j, k, n
    real                        :: temp, m

    n = size(s, 1)

    if(n == 0) then
        error = -1 
        return
    end if

    if(n /= size(s, 2)) then
        error = -2 
        return
    end if

    if(n /= size(s, 2)) then 
        error = -3 
        return
    end if

    error = 0
    do i = 1, n-1
        ksave = maxloc(abs(s(i:n, i)))
        k = ksave(1) + i - 1
        if(s(k, i) == 0) then
            error = -4
            return
        end if

        if(k /= i) then
            temp_array = s(i, :)
            s(i, :) = s(k, :)
            s(k, :) = temp_array
            temp = c(i)
            c(i) = c(k)
            c(k) = temp
        end if

        do j = i + 1, n
            m = s(j, i)/s(i, i)
            s(j, :) = s(j, :) - m*s(i, :)
            c(j) = c(j) - m*c(i)
        end do
    end do

     end subroutine gaussion_ellimination
     !==========================================================================================

   !================= Subroutine back_substitution ========================================
     subroutine back_substitution(s, c)

    double precision, dimension(:,:), intent(in) :: s
    double precision, dimension(:),   intent(in out) :: c

    real    :: w
    integer :: i, j, n

    n = size(c)

    do i = n, 1, -1
        w = c(i)
        do j = i + 1, n
            w = w - s(i, j)*c(j)
        end do
        c(i) = w/s(i, i)
    end do

      end subroutine back_substitution

Where s(i, j) is the matrix of coefficients of the system and c(i) is the solution vector.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

恍梦境° 2024-12-28 17:29:52

您绝对不应该编写自己的高斯消除或类似矩阵运算例程。像 LAPACK 这样无处不在的软件包将比您自己编写的任何软件包拥有更快、更准确的版本;在 LAPACK 中,您可以结合使用 _getrf_getrs 用于一般矩阵,但如果您有带状或对称矩阵矩阵也有针对这些的特殊例程。您应该会发现为您的系统找到并安装优化的线性代数包非常容易。 (查找诸如 atlas、flame 或 gotoblas 之类的包名称)。

在上面的代码中,在 gaussian_solve 例程(即 temp_array)的开头附近应该有一个call gaussion_ellimination(s, c, error) (以及 tempmw)也应该是双精度,以避免双精度矩阵丢失精度,检查是否与浮动完全相等零点是有风险的策略,我会检查你的输入矩阵 - 如果存在任何线性简并,你将得到所有 NaN(特别是如果它是最后一个行向量,与任何早期的向量线性简并)。

如果这不能解决问题,您可以使用信号 NaN 找出问题首先出现的位置 - 强制 gfortran 首先停止程序 NaN - 但是你最好只使用现有的包来处理这样的事情,这些包是由研究集合数值解的人编写的线性方程组多年来。

You should never write your own routines for gaussian elimination or similar matrix operations. Ubiquitous packages like LAPACK will have faster, more accurate versions than anything you're likely to code yourself; in LAPACK you'd use a combination of _getrf and _getrs for general matricies, but if you have banded or symettric matricies there are special routines for those, too. You should find it quite easy to find and install an optimized linear algebra package for your system. (Look for package names like atlas or flame or gotoblas).

In the code above, there should presumably be a call gaussion_ellimination(s, c, error) near the start of your gaussian_solve routine, your temp_array (and temp and m and w) should also be double precision to avoid losing precision from your double precision matrix, checking for exact equality to floating point zero is a risky strategy, and I'd check your input matrix - if there are any linear degeneracies you will get all NaNs (particularly if it's the last row vector which is linearly degenerate with any of the earlier ones).

If that doesn't fix the problem, you can use signaling NaNs to find out where the problem first arises - Force gfortran to stop program at first NaN - but you're really better off just using existing packages for stuff like this, which have been written by people who have studied the numerical solution of sets of linear equations for years.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文