Fortran中的无穷大

12

在Fortran中,设置一个变量为+Infinity的最安全的方法是什么?目前我正在使用:

program test
  implicit none
  print *,infinity()
contains
  real function infinity()
    implicit none
    real :: x
    x = huge(1.)
    infinity = x + x
  end function infinity
end program test

但我想知道是否有更好的方法?

6个回答

11

如果你的编译器支持ISO TR 15580 IEEE算术,这是所谓的Fortran 2003标准的一部分,那么你可以使用ieee_*模块中的过程。

PROGRAM main

  USE ieee_arithmetic

  IMPLICIT NONE

  REAL :: r

  IF (ieee_support_inf(r)) THEN
    r = ieee_value(r,  ieee_negative_inf)
  END IF

  PRINT *, r

END PROGRAM main

1

我不确定下面的解决方案是否适用于所有编译器,但这是一种很好的数学方法,可以将无穷大表示为-log(0)。

program test
  implicit none
  print *,infinity()
contains
  real function infinity()
    implicit none
    real :: x
    x = 0
    infinity=-log(x)
  end function infinity
end program test

也可以很好地处理复杂变量。


如果您不启用FPE陷阱,它将在符合IEEE标准的机器上运行。但是,如果您使用无穷大进行操作,那么这样做就很愚蠢了。 - Vladimir F Героям слава

1

我不会依赖编译器来支持IEEE标准,而是基本上做你所做的事情,但有两个变化:

  1. 我不会添加huge(1.)+huge(1.),因为在一些编译器上,你可能会得到-huge(1.)+1 --- 这可能会导致内存泄漏(不知道原因,但这是实验事实,可以说)。

  2. 你在此处使用'real'类型。我个人更喜欢将所有我的浮点数保持为real*8,因此所有浮点常量都带有d0限定符,例如:huge(1.d0)。当然,这不是规则; 有些人更喜欢同时使用realreal*8


2
real*8double precision(1.d0)不一定是相同的实数类型。当然,使用单精度还是双精度并不是个人喜好的问题,而是基于数学论证和测试的考虑。 - Vladimir F Героям слава

0

我不知道最安全的方法,但我可以提供一种替代方法。我是这样学会做的:

PROGRAM infinity
  IMPLICIT NONE
  INTEGER :: inf
  REAL :: infi
  EQUIVALENCE (inf,infi) !Stores two variable at the same address
  DATA inf/z'7f800000'/ !Hex for +Infinity
  WRITE(*,*)infi
END PROGRAM infinity

如果您在表达式中使用异常值(我认为这通常不可取),则应仔细注意编译器如何处理它们,否则可能会得到一些意外的结果。

0
对于任何来到这个帖子的人,定义inf/-inf的十六进制转换可以很容易地完成:
use iso_fortran_env, only: sp => real32, dp => real64, qp => real128
!> single precision infinities
real(sp) :: pinf_sp = real(z'7f800000',sp) 
real(sp) :: ninf_sp = real(z'ff800000',sp) 
!> double precision infinities
real(dp) :: pinf_dp = real(z'7ff0000000000000',dp)
real(dp) :: ninf_dp = real(z'fff0000000000000',dp)
!> quadruple precision infinities
real(qp) :: pinf_qp = real(z'7fff0000000000000000000000000000',qp)
real(qp) :: ninf_qp = real(z'ffff0000000000000000000000000000',qp)

-1
这对我来说似乎有效。 定义一个参数
double precision,parameter :: inf = 1.d0/0.d0

然后在if测试中使用它。

  real :: sng
  double precision :: dbl1,dbl2

  sng = 1.0/0.0
  dbl1 = 1.d0/0.d0
  dbl2 = -log(0.d0)

  if(sng == inf) write(*,*)"sng = inf"
  if(dbl1 == inf) write(*,*)"dbl1 = inf"
  if(dbl2 == inf) write(*,*)"dbl2 = inf"
  read(*,*)

使用ifort编译并运行,我得到以下结果

sng = inf
dbl1 = inf
dbl2 = inf

这个不起作用,至少在gfortran中是如此。它会引发编译器错误。 - Paul Wintz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接