Бесконечность в Фортране
каков самый безопасный способ установить переменную в + бесконечность в Fortran? На данный момент я использую:
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
но мне интересно, есть ли лучший способ?
5 ответов
Если ваш компилятор поддерживает 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
Я не уверен, работает ли решение ниже на всех компиляторах, но это хороший математический способ достижения бесконечности как-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
также хорошо работает для сложных переменных.
Я бы не стал полагаться на компилятор для поддержки стандарта IEEE и делать в значительной степени то, что вы сделали, с двумя изменениями:
Я бы не добавить
huge(1.)+huge(1.)
, Так как на некоторых компиляторах вы можете получить-huge(1.)+1
- - - и это может вызвать утечку памяти (не знаю причины, но это экспериментальный факт, так сказать).вы используете
real
здесь типов. Я лично предпочитаю держать все мои числа с плавающей запятой какreal*8
, следовательно, все константы float квалифицируются сd0
, например:huge(1.d0)
. Это не правило, конечно, некоторые люди предпочитают использовать какreal
иreal*8
- s.
Я не знаю о safest, но я могу предложить вам альтернативный метод. Я научился делать это так:--2-->
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
Если вы используете исключительного значения в выражениях (я не думаю, что это вообще целесообразно), вы должны обратить пристальное внимание на то, как ваш компилятор обрабатывает их, вы могли бы получить неожиданные результаты.
Это, кажется, работает для меня. Определите параметр
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