Наличие параметра (постоянной) переменной со значением NaN в FORTRAN
Можно ли установить переменную параметра с NaN? и иметь это в определенном модуле. Я хочу использовать его для инициализации некоторых других переменных. Поэтому я столкнусь с ошибкой времени выполнения, если они не будут обновлены, а не с симуляциями, запущенными с некоторыми случайными числами. Я использую GFORTRAN.
4 ответа
Это возможно. Сначала вы должны выяснить, какая битовая комбинация представляет одно из возможных значений NaN. Вы можете сохранить битовый шаблон в целое число:
use, intrinsic :: iso_fortran_env
real(real64) x
integer(int64) i
x = 0
x = 0/x
print *, x
print *, transfer(x, i)
end
Это дает: -2251799813685248
Затем вы можете инициализировать ваши переменные, используя
real(real64), parameter :: nan64 = transfer(-2251799813685248_int64, 1._real64)
Аналогично для 32-битных переменных вы получаете целое число -4194304, так что вы можете сделать
real(real32), parameter :: nan32 = transfer(-4194304_int32, 1._real32)
Многие компиляторы имеют возможность сделать это для вас для всех реальных переменных. Как показывает Франческа, в гфортране это -finit-real=nan
, Делая это вручную, вы получите лучший контроль.
Отказ от ответственности: будьте осторожны при переходе на другую платформу. Порядковые значения и другие вопросы могут сыграть свою роль, хотя я думаю, что все может быть в порядке. Я предположил, что процессор соответствует IEEE.
Смотрите ответ Франческа на альтернативу, которая использует стандартную функцию. К сожалению, это не применимо для parameter
константы, но это полезно.
В дополнение к ответу Владимира Ф. я упомяну, что gfortran 5.0 (но не ранее) поддерживает встроенные модули IEEE.
Вместо
real x
x=0
x=0/x
можно использовать
use, intrinsic :: iso_fortran_env
use, intrinsic :: ieee_arithmetic
integer(int32) i
real(real32) x
x = ieee_value(x, ieee_quiet_nan)
i = transfer(x,i)
Это дает вам небольшую гибкость в зависимости от того, какое из значений NaN вы получаете. Вам также не нужно беспокоиться о сигнале недействительного флага. [Но обратите внимание, что просят ieee_signaling_nan
может и не дать вам этого.]
Обратите внимание, что ieee_value()
не может использоваться непосредственно при инициализации: ссылка на него не является константным выражением. Для такого использования используйте этот подход, чтобы получить битовую комбинацию и применить метод другого ответа.
Вам также необходимо убедиться, что есть поддержка функций для каждого типа данных.
Если вы застряли с GFortran, который не имеет встроенного IEEE, но имеет встроенный iso_c_binding (как тот, который необходим для сборки R в Windows), следующее работает и эквивалентно C и R NaN (проходит is.nan
на R):
real(kind = c_double), parameter :: ONE = 1_c_double
real(kind = c_double), parameter :: NAN = TRANSFER(z'7FF0000000000001', ONE)
Что интересно, real(kind = c_double), parameter :: NAN = TRANSFER(z'7FF0000000000001', 1_c_double)
не проходит проверку is.nan
,
Как указывал francescalus и в этом обсуждении , результат
ieee_value
не может быть присвоено . Другой подход заключается в использовании
protected
переменная модуля вместо
parameter
. Однако тогда необходимо вызвать функцию инициализации модели в начале программы.
module nan_module
implicit none
real, protected :: nan_real
contains
subroutine init_nan_module
use, intrinsic :: ieee_arithmetic
implicit none
nan_real = ieee_value(nan_real, ieee_quiet_nan)
end subroutine
end module nan_module
program test
use nan_module, only: init_nan_module, nan_real
implicit none
real :: x
call init_nan_module()
x = nan_real
write(*,*) x, 'isnan', isnan(x)
end program test