web-dev-qa-db-fra.com

Existe-t-il un moyen standard de vérifier Infinite et NaN dans Fortran 90/95?

J'ai essayé de trouver un moyen conforme aux normes de vérifier les valeurs Infinite et NaN dans Fortran 90/95, mais cela s'est avéré plus difficile que je ne le pensais.

  • J'ai essayé de créer manuellement des variables Inf et NaN en utilisant la représentation binaire décrite dans IEEE 754, mais je n'ai trouvé aucune telle fonctionnalité.
  • Je connais le module intrinsèque ieee_arithmetic Dans Fortran 2003 avec les fonctions intrinsèques ieee_is_nan() et ieee_is_finite(). Cependant il n'est pas supporté par tous les compilateurs ( notamment gfortran à partir de la version 4.9).

Définir l'infini et NaN au début comme pinf = 1. / 0 Et nan = 0. / 0 Me semble hackeux et à mon humble avis peut poser des problèmes de construction - par exemple, si certains compilateurs vérifient cela au moment de la compilation, il faudrait fournir un spécial drapeau.

Existe-t-il un moyen de mettre en œuvre la norme Fortran 90/95?

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

et isnan()?

20
astrojuanlu

La manière simple sans utiliser le ieee_arithmatic Est de procéder comme suit.

Infinity: Définissez votre variable infinity = HUGE(dbl_prec_var) (ou, si vous l'avez, une variable quad précision). Ensuite, vous pouvez simplement vérifier si votre variable est infinie par if(my_var > infinity).

NAN : C'est encore plus facile. Par définition, NAN n'est égal à rien, même à lui-même. Comparez simplement la variable à elle-même: if(my_var /= my_var).

22
Kyle Kanos

Je n'ai pas assez de représentant pour commenter, je vais donc "répondre" à la suggestion de Rick Thompson de tester l'infini.

if (A-1 .eq. A) 

Cela sera également vrai si A est un très grand nombre à virgule flottante, et 1 est inférieur à la précision de A.

Un test simple:

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

les sorties:

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!!!
3
Ethan Gutmann

Non.

Les parties saillantes de IEEE_ARITHMETIC pour générer/vérifier les NaN sont assez faciles à écrire pour gfortran pour une architecture particulière.

2
IanH

J'ai utilisé:

  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

Cela affichera 'Got a problem' pour number = 0.0D0, 1.0D0/0.0D0, 0.0D0/0.0D0, SQRT (-2.0D0), ainsi que pour les débordements et les débordements tels que number = EXP (1.0D800) ou number = EXP (-1,0D800). Notez qu'en général, des choses comme number = EXP (1.0D-800) ne feront que définir number = 1.0 et produiront un avertissement au moment de la compilation, mais le programme affichera "We are OK", ce que je trouve acceptable.

OL.

1
Otto Linsuain

Pour Fortran, 1/infini = 0 donc, divisez votre variable par zéro, c'est-à-dire

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

voici votre chèque à l'infini. Aucune complication nécessaire.

0
Adrian Barbuio

Non.

Il n'y a pas non plus de méthode conforme aux normes pour vérifier les infinis ou les NaN dans Fortran 90/95, ni de méthode conforme aux normes. Il n'existe aucun moyen conforme aux normes de définir l'un ou l'autre de ces quasi-nombres dans Fortran 90/95.

0