在 Fortran 应用程序中接收 NaN 值
我正在开发一个 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您绝对不应该编写自己的高斯消除或类似矩阵运算例程。像 LAPACK 这样无处不在的软件包将比您自己编写的任何软件包拥有更快、更准确的版本;在 LAPACK 中,您可以结合使用 _getrf 和 _getrs 用于一般矩阵,但如果您有带状或对称矩阵矩阵也有针对这些的特殊例程。您应该会发现为您的系统找到并安装优化的线性代数包非常容易。 (查找诸如 atlas、flame 或 gotoblas 之类的包名称)。
在上面的代码中,在
gaussian_solve
例程(即temp_array
)的开头附近应该有一个call gaussion_ellimination(s, c, error)
(以及temp
和m
和w
)也应该是双精度,以避免双精度矩阵丢失精度,检查是否与浮动完全相等零点是有风险的策略,我会检查你的输入矩阵 - 如果存在任何线性简并,你将得到所有 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 yourgaussian_solve
routine, yourtemp_array
(andtemp
andm
andw
) 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.