Fortran 语言中的无穷大

发布于 2024-10-17 17:09:21 字数 299 浏览 2 评论 0原文

在 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

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

What is the safest way to set a variable to +Infinity in Fortran? At the moment I am using:

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

but I am wondering if there is a better way?

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

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

发布评论

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

评论(6

我的奇迹 2024-10-24 17:09:21

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

If your compiler supports ISO TR 15580 IEEE Arithmetic which is a part of so-called Fortran 2003 standard than you can use procedures from ieee_* modules.

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
世界如花海般美丽 2024-10-24 17:09:21

我不会依赖编译器来支持 IEEE 标准,并且会做与您所做的几乎相同的事情,但有两个更改:

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

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

I would not rely on the compiler to support the IEEE standard and do pretty much what you did, with two changes:

  1. I would not add huge(1.)+huge(1.), since on some compilers you may end up with -huge(1.)+1 --- and this may cause a memory leak (don't know the reason, but it is an experimental fact, so to say).

  2. You are using real types here. I personally prefer to keep all my floating-point numbers as real*8, hence all float constants are qualified with d0, like this: huge(1.d0). This is not a rule, of course; some people prefer using both real-s and real*8-s.

明明#如月 2024-10-24 17:09:21

我不确定下面的解决方案是否适用于所有编译器,但这是一种很好的数学方法,可以达到 -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

对于复杂变量也很有效。

I'm not sure if the solution bellow works on all compilers, but it's a nice mathematical way of reaching infinity as -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

Also works nicely for complex variables.

千柳 2024-10-24 17:09:21

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

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

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

I don't know about safest, but I can offer you an alternative method. I learned to do it this way:

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

If you are using exceptional values in expressions (I don't think this is generally advisable) you should pay careful attention to how your compiler handles them, you might get some unexpected results otherwise.

淡莣 2024-10-24 17:09:21

对于任何来到此线程的人,可以通过以下方式轻松完成定义 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)

For anyone coming to this thread, the hexadecimal conversion to define inf/-inf can be easily done by:

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)
メ斷腸人バ 2024-10-24 17:09:21

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

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

This seems to work for me.
Define a parameter

double precision,parameter :: inf = 1.d0/0.d0

Then use it in if tests.

  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(*,*)

When compiled with ifort & run, I get

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