Есть ли стандартный способ проверки Infinite и NaN в Fortran 90/95?

Я пытался найти совместимый со стандартами способ проверки значений Infinite и 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, кажется мне хакерским, и ИМХО может вызвать некоторые проблемы со сборкой - например, если некоторые компиляторы проверяют это во время компиляции, нужно будет указать специальный флаг.

Есть ли способ реализовать в стандартном Fortran 90/95?

function isinf(x)
! Returns .true. if x is infinity, .false. otherwise
...
end function isinf

и isnan()?


person astrojuanlu    schedule 30.06.2013    source источник
comment
gnu fortran 4.10 исправляет это   -  person Susanne Oberhauser    schedule 19.04.2015
comment
GCC 5 и более поздние версии поддерживают IEEE_ARITHMETIC, но поддержка более старых версий по-прежнему является проблемой и будет существовать еще долгое время.   -  person Vladimir F    schedule 23.05.2016


Ответы (8)


Простой способ без использования ieee_arithmatic состоит в том, чтобы сделать следующее.

Бесконечность: определите свою переменную infinity = HUGE(dbl_prec_var) (или, если она у вас есть, переменную с четырехкратной точностью). Затем вы можете просто проверить, является ли ваша переменная бесконечностью на if(my_var > infinity).

НЭН: Это еще проще. По определению NAN ничему не равен, даже самому себе. Просто сравните переменную с самой собой: if(my_var /= my_var).

person Kyle Kanos    schedule 30.06.2013
comment
Странно, что никто больше не упомянул случай NaN. Я думаю, они были обеспокоены тем, что вы можете использовать фортран на процессоре, отличном от IEEE? Кроме того, проверка NaN очень надежна. С другой стороны, проверка бесконечности немного менее элегантна, так как зависит от типа данных. - person amaurea; 01.07.2013
comment
@amaurea: вы можете решить проблему с типом данных, используя INTERFACE и связав несколько типов, которые вы можете использовать, с одним и тем же MODULE PROCEDURE. - person Kyle Kanos; 01.07.2013
comment
@IanH: Вы могли бы разумно установить infinity = 1.e100_dp и при этом получить хорошую проверку бесконечности. Даже при использовании малых масштабов (например, 1e-24 м) для описания больших масштабов (например, 1e+24 м) вы все равно далеки от 1e100. - person Kyle Kanos; 01.07.2013
comment
Спасибо за ответ, и хороший улов о MODULE PROCEDURE. С ним можно сделать очень чистый интерфейс. Если мой код того стоит, я могу его выпустить. Спасибо еще раз! - person astrojuanlu; 01.07.2013
comment
Оптимизатор действительно оптимизирует проверку, если запрашивается fast_math или аналогичный. Увы, он даже оптимизирует встроенную функцию isnan gfortran. Программист должен позаботиться об этом, когда он запрашивает небезопасную быструю математику и все еще хочет обнаружить NaN. - person Vladimir F; 23.05.2016
comment
ОГРОМНЫЙ - самая большая не бесконечность; условие myvar > HUGE(myvar) должно быть истинным только в том случае, если myvar бесконечен, но называть HUGE(myvar) бесконечностью вводит в заблуждение. - person ShadSterling; 02.11.2016
comment
Какая часть этого ответа функциональна по сравнению со стандартом? Другими словами, так ли это должно быть сделано, или это просто так можно сделать? - person jvriesem; 26.01.2019
comment
@jvriesem с использованием iee_arithmetic - это то, как это должно быть сделано (поэтому, если ваш компилятор не поддерживает его, получите другой/лучший компилятор). Это совместимый со стандартами способ, который достаточно функционален: переменные бесконечны, когда они больше значения, не имеющего смысла для кода (и бесконечно малы, когда меньше определенного значения); Однако проверка NaN может быть оптимизирована с помощью некоторых компиляторов. - person Kyle Kanos; 27.01.2019

У меня недостаточно представителей, чтобы комментировать, поэтому я «отвечу» на предложение Рика Томпсона по тестированию бесконечности.

if (A-1 .eq. A) 

Это также будет верно, если A — очень большое число с плавающей запятой, а 1 меньше точности A.

Простой тест:

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!!!
person Ethan Gutmann    schedule 31.12.2014

No.

Существенные части IEEE_ARITHMETIC для генерации/проверки NaN достаточно легко написать для gfortran для конкретной архитектуры.

person IanH    schedule 30.06.2013
comment
Что касается вашего второго утверждения, они, похоже, не согласны с gcc. gnu.org/ml/gcc-bugs/2012-10/msg00580.html или я что-то упустил? - person astrojuanlu; 30.06.2013
comment
Кстати, я добавил ссылку на соответствующую ошибку gfortran (которая датируется 2006 годом и имеет статус NEW). - person astrojuanlu; 30.06.2013
comment
Написание всех IEEE_ARITHMETIC для всех архитектур, поддерживаемых gfortran, с чем и связана эта ошибка, было бы сложно! Написание битов выбора, которые генерируют/проверяют наличие NaN, в определенной архитектуре (например, x64) довольно просто. См. sites.google.com/site/tprincesite/Home/gfortran-ieee. -арифметика для одного примера Тима Принса, который опирается на неравенство любых двух NaN, альтернативный подход заключается в использовании битовых встроенных функций Fortran для генерации/тестирования конкретных шаблонов, которые указывают NaN. (Подробнее см. исходную ошибку gfortran 29383.) - person IanH; 30.06.2013

Я использовал:

  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

Это напечатает «Есть проблема» для числа = 0.0D0, 1.0D0/0.0D0, 0.0D0/0.0D0, SQRT (-2.0D0), а также для переполнения и потери значимости, таких как число = EXP (1.0D800) или число = ЭКСПЕРИМЕНТ(-1.0D800). Обратите внимание, что, как правило, такие вещи, как number = EXP(1.0D-800), просто устанавливают number = 1.0 и выдают предупреждение во время компиляции, но программа печатает «We are OK», что я считаю приемлемым.

OL.

person Otto Linsuain    schedule 23.05.2016
comment
Вопрос требует NotANumber, но ваш пример проверяет конечность. Он также будет обнаруживать +Inf и -Inf как ложные срабатывания. Также обратите внимание, что вопрос действительно в основном интересовался тем, что делать, когда IEEE_ARITHMETIC недоступен, и спрашивает, как это сделать с помощью Fortran 90/95. - person Vladimir F; 23.05.2016
comment
Вдобавок к опасениям Владимира Ф. нет никакой гарантии, что даже с ieee_arithmetic верно ieee_support_datatype(test). Если это не так, то ieee_is_finite(test) рассматривать не разрешается. - person francescalus; 23.05.2016
comment
Я был слишком резок, вопрос также требует эквивалента IEEE_IS_FINITE(). Но дело в том, что ОП знает, что он существует, но запрашивает альтернативу. - person Vladimir F; 23.05.2016

No.

В Fortran 90/95 также нет совместимого со стандартами способа проверки бесконечности или NaN, и не может быть совместимого со стандартами способа. В Фортране 90/95 не существует совместимого со стандартами способа определения любого из этих квазичисел.

person High Performance Mark    schedule 30.06.2013
comment
Ну, то есть в рамках стандарта IEEE с плавающей запятой. - person astrojuanlu; 01.07.2013

Для Фортрана 1/бесконечность=0, таким образом, разделите переменную на ноль, т.е.

program test
implicit none
real :: res
integer :: i

do i=1,1000000
    res=-log((1.+(10**(-real(i))))-1.)
    print*,i,res
    if ((1./res)==0.) then
        exit
    end if
end do

end program

вот твой чек на бесконечность. Нет необходимости в усложнении.

person Adrian Barbuio    schedule 03.01.2020

для тестирования NaN ни одна из вещей не работала, например, если тестировать реальный s2p, чтобы увидеть, является ли это NaN, тогда

if(isnan(s2p)) 

не работал в gfortran и не

if(s2p.ne.s2p). 

Единственное, что сработало, это

if(.not.s2p<1.and..not.s2p>1)  

хотя, чтобы убедиться, что вы можете добавить

if(.not.s2p<1.and..not.s2p>1.and..not.s2p==1)    
person dan hayes    schedule 21.08.2020

Для Inf кажется, что если (A-1 .eq. A) верно, то A является Inf

person Rick Thompson    schedule 12.11.2014
comment
Может быть, вы захотите уточнить немного больше. - person CinCout; 12.11.2014