Есть ли стандартный способ проверить Infinite и NaN в Fortran 90/95?
Я пытался найти совместимый со стандартами способ проверить бесконечные и NaN значения в Fortran 90/95, но это оказалось сложнее, чем я думал.
- я попытался вручную создать переменные Inf и NaN, используя двоичное представление, описанное в IEEE 754, но я не нашел такой функциональности.
- Я осознаю внутреннюю
ieee_arithmetic
модуль в Fortran 2003 сieee_is_nan()
иieee_is_finite()
встроенные функции. Однако он не поддерживается всеми компиляторами (особенно gfortran начиная с версии 4.9).
определение бесконечности и NaN в начале вроде pinf = 1. / 0
и nan = 0. / 0
кажется мне хакерским, и IMHO может вызвать некоторые проблемы с построением - например, если некоторые компиляторы проверяют это во время компиляции, нужно будет предоставить специальный флаг.
есть ли способ, который я могу реализовать в стандартном Fortran 90/95?
function isinf(x)
! Returns .true. if x is infinity, .false. otherwise
...
end function isinf
и isnan()
?
6 ответов
самый простой способ без использования ieee_arithmatic
сделать следующее.
бесконечность: определить переменную infinity = HUGE(dbl_prec_var)
(или, если у вас есть, переменная точности quad). Затем вы можете просто проверить, является ли ваша переменная бесконечностью по if(my_var > infinity)
.
НЭН: это еще проще. По определению, NaN не равен ничему, даже самому. Просто сравните переменную с самой собой:if(my_var /= my_var)
.
у меня недостаточно репутации, чтобы прокомментировать, поэтому я "отвечу" на предложение Рика Томпсона для тестирования бесконечности.
if (A-1 .eq. A)
Это также будет верно, если A-очень большое число с плавающей запятой и 1
ниже точности А.
простой тест:
subroutine test_inf_1(A)
real, intent(in) :: A
print*, "Test (A-1 == A)"
if (A-1 .eq. A) then
print*, " INFINITY!!!"
else
print*, " NOT infinite"
endif
end subroutine
subroutine test_inf_2(A)
real, intent(in) :: A
print*, "Test (A > HUGE(A))"
if (A > HUGE(A)) then
print*, " INFINITY!!!"
else
print*, " NOT infinite"
endif
end subroutine
program test
real :: A,B
A=10
print*, "A = ",A
call test_inf_1(A)
call test_inf_2(A)
print*, ""
A=1e20
print*, "A = ",A
call test_inf_1(A)
call test_inf_2(A)
print*, ""
B=0.0 ! B is necessary to trick gfortran into compiling this
A=1/B
print*, "A = ",A
call test_inf_1(A)
call test_inf_2(A)
print*, ""
end program test
выходы:
A = 10.0000000
Test (A-1 == A)
NOT infinite
Test (A > HUGE(A))
NOT infinite
A = 1.00000002E+20
Test (A-1 == A)
INFINITY!!!
Test (A > HUGE(A))
NOT infinite
A = Infinity
Test (A-1 == A)
INFINITY!!!
Test (A > HUGE(A))
INFINITY!!!
нет.
основные части IEEE_ARITHMETIC для генерации / проверки NaN достаточно легко написать для gfortran для конкретной архитектуры.
я использовал:
PROGRAM MYTEST
USE, INTRINSIC :: IEEE_ARITHMETIC, ONLY: IEEE_IS_FINITE
DOUBLE PRECISION :: number, test
number = 'the expression to test'
test = number/number
IF (IEEE_IS_FINITE(test)) THEN
WRITE(*,*) 'We are OK'
ELSE
WRITE(*,*) 'Got a problem'
END IF
WRITE(*,*) number, test
END PROGRAM MYTEST
это будет печатать "Got a problem" для числа = 0.0D0, 1.0D0 / 0.0D0, 0.0D0 / 0.0D0, SQRT(-2.0D0), а также для переполнений и недотоков, таких как number = EXP(1.0D800) или число = EXP (-1.0D800). Обратите внимание, что обычно такие вещи, как number = EXP(1.0 D-800), просто устанавливают number = 1.0 и выдают предупреждение во время компиляции, но программа напечатает "мы в порядке", что я нахожу приемлемым.
OL.
нет.
также нет совместимого со стандартами способа проверки бесконечностей или NaNs в Fortran 90/95, и не может быть совместимого со стандартами способа. В Fortran 90/95 отсутствует соответствующий стандартам способ определения любого из этих квази-чисел.