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.
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()
?
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)
.
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!!!
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.
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.
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.
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.