【问题标题】:Infinity in FortranFortran 中的无穷大
【发布时间】:2011-06-27 23:42:32
【问题描述】:

在 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

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

【问题讨论】:

    标签: fortran infinity


    【解决方案1】:

    如果您的编译器 supports 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
    

    【讨论】:

      【解决方案2】:

      我不会依赖编译器来支持 IEEE 标准并做你所做的几乎所有事情,但有两个变化:

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

      2. 您在此处使用real 类型。我个人更喜欢将所有浮点数保留为real*8,因此所有浮点常量都使用d0 限定,如下所示:huge(1.d0)。当然,这不是规则;有些人喜欢同时使用real-s 和real*8-s。

      【讨论】:

      • real*8double precision (1.d0) 不一定是同一类。当然,使用单精度还是双精度不是个人喜好的问题,而是数学论证和测试的问题。
      【解决方案3】:

      我不确定下面的解决方案是否适用于所有编译器,但它是一种很好的数学方法,可以像 -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 的机器上工作。但是,如果您使用无穷大,这样做就很愚蠢。
      【解决方案4】:

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

      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
      

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

      【讨论】:

        【解决方案5】:

        这似乎对我有用。 定义一个参数

        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 & run 编译时,我得到

        sng = inf
        dbl1 = inf
        dbl2 = inf
        

        【讨论】:

        • 这不起作用,至少在 gfortran 中是这样。它会引发编译器错误。
        猜你喜欢
        • 1970-01-01
        • 2022-08-12
        • 2019-03-19
        • 2011-02-02
        • 1970-01-01
        • 2013-11-29
        • 1970-01-01
        • 1970-01-01
        • 2017-11-03
        相关资源
        最近更新 更多