Наличие параметра (постоянной) переменной со значением 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
Другие вопросы по тегам