Fortran program doesn't update a variable's value properly - fortran

I'm trying to implement a Bisection method subroutine in Fortran to solve a computational science program and Fortran is doing some weird things. So the goal of the program is to find the solution of a transcendental equation for some parameter e0 which is updated every step in a for loop and passed to the subroutine.
The problems are:
e0 is not updated as it should. The value of e0 goes from 0.1799... to 0.8999... in one single iteration, while in theory it should take the program 9 interations to get there. Why is this happening?
The print statements aren't printed as they should (see output below). We expect an "out 1" print, some "in" prints (printed when subroutine f1 is called by subroutine Bisection some times), then "out 2" print (with the new e0 value), some "in" prints, etc. But we see the first "out 1" print, some "in" prints and then only "out" prints. Does this mean the subroutine f1 is only called between "out 1" and "out 2"? (it should be called between every "out" print)
I have used Fortran77 for numerical solving for a couple years and never encountered something like this, but it's been nearly 6 months since I don't program anything so maybe I missed an important thing.
Code:
program roots
implicit none
double precision A,B,eps,e0,e1
integer i,niter
external f1
A = 1d-1
B = 9d-1
eps = 10d-6
open(9,file='dades.dat',status='old')
do i=1,9
e0 = i*(B-A)/10 + A
c Here is the first print. 'Out' meaning outside the subroutine
print *, 'out', i, e0
call Bisection(A,B,eps,f1,niter,e1,e0)
write (9,'(2(f10.5))') e0,e1
end do
close(9)
end program roots
subroutine Bisection(A,B,eps,f,niter,xroot,e0)
implicit none
double precision A,B,eps,xroot,fuc,fua,e0
integer niter,i
niter = nint(log((B-A)/eps)/log(2.))+1
do i=1,niter
xroot = (A+B)/2
c Here the subroutine which uses e0 is called twice
call f(xroot,fuc,e0)
call f(A,fua,e0)
if (fuc .eq. 0) return
if (fuc*fua .lt. 0.) then
B = xroot
else
A = xroot
end if
end do
return
end subroutine Bisection
subroutine f1(x,f,e0)
implicit none
double precision x,f,e0
c Here is the second print. 'In' meaning inside the subroutine
print *, 'in', e0
f = e0+1
end subroutine f1
Output:
out 1 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
in 0.17999999999999999
out 2 0.89999511718750003
out 3 0.89999572753906254
out 4 0.89999633789062505
out 5 0.89999694824218746
out 6 0.89999755859374997
out 7 0.89999816894531248
out 8 0.89999877929687500
out 9 0.89999938964843751

I have finally found out the issue after a deep look through the code. The problem is that variables A and B are both input and output because they are modified inside the subroutine. Because of that, when the subroutine is called the first time, it changes A and B's value (which is different from the one set at the beginning of the code). The rest are issues originated by this.
The solution was to reset the values at the beginning each iteration as shown below:
program roots
implicit none
double precision A,B,eps,e0,e1
integer i,niter
external f1
eps = 10d-6
open(9,file='dades.dat',status='old')
do i=1,9
A = 1d-1
B = 9d-1
e0 = i*(B-A)/10 + A
c Here is the first print. 'Out' meaning outside the subroutine
print *, 'out', i, e0
call Bisection(A,B,eps,f1,niter,e1,e0)
write (9,'(2(f10.5))') e0,e1
end do
close(9)
end program roots
subroutine Bisection(A,B,eps,f,niter,xroot,e0)
implicit none
double precision A,B,eps,xroot,fuc,fua,e0
integer niter,i
niter = nint(log((B-A)/eps)/log(2.))+1
do i=1,niter
xroot = (A+B)/2
c Here the subroutine which uses e0 is called twice
call f(xroot,fuc,e0)
call f(A,fua,e0)
if (fuc .eq. 0) return
if (fuc*fua .lt. 0.) then
B = xroot
else
A = xroot
end if
end do
return
end subroutine Bisection
subroutine f1(x,f,e0)
implicit none
double precision x,f,e0
c Here is the second print. 'In' meaning inside the subroutine
print *, 'in', e0
f = e0+1
end subroutine f1

Related

Problems with do while implementation

I am having problems with a do while implementation for a sine taylor series. Editing the do loop to do bb = 1, 10 , 2 gives an expected result well within the margin of error, however when running the desired implementation of the do loop (do while(abs(sineseries) - accuracy > 0), will always give an answer equal to 1. So I have narrowed the possibilities down to the do while loop implementation being faulty.
program taylor
implicit none
real :: x
real :: sineseries, nfactsine
real, parameter :: accuracy = 1.e-10
integer :: signum, bb
nfactsine = 1
signum = 1
write(*,*) "Write your input value"
read(*,*) x
sineseries = 0
do while(abs(sineseries) - accuracy > 0)
sineseries = sineseries + (signum*x**bb)/nfactsine
nfactsine = nfactsine*(bb+1)*(bb+2)
signum = -signum
end do
write(*,*) sineseries, sin(x)
end program taylor
The two types of loops are not doing the same thing.
In the loop
do bb=1, 10, 2
...
end do
you have loop control with variable bb. This variable takes the values 1, 3, ..., 9 at iterations as the loop proceeds.
The do while does not have this control: you must replicate the increment of bb manually:
bb=1
do while (...)
...
bb=bb+2
end do
As Pierre de Buyl commented, you also have an error in the termination condition for the indefinite iteration count. The condition initially evaluates as false, so the loop body isn't executed even once.

Compiler won't calculate variable unless I print it""

So apparently, depending in wether i tell the program to print the variable i, or not, I get different results that should not have anything to do with wether i print it our or not.
PROGRAM hello
IMPLICIT NONE
integer :: n,i, mini
logical :: leave = .false.
read*, n
print*, is_prime(n)
!!---------------------------------------------------------------------
do i=n, n/2, -1
print*, "I= ", i !!if you comment out this line, the result will be different than if you were to keep it, try it out yourselves
if(is_prime(i)) then
mini = i
end if
end do
print*, "the lowest prime number between your number and its half is: ", mini
!!----------------------------------------------------------
CONTAINS
logical function is_prime(n)
integer::n,i
do i=2,n
if(mod(n,i) == 0 .and. (i/=1 .and. i/=n) ) then
is_prime = .false.
elseif(mod(n,i) /=0 .and. i == n-1 .and. is_prime .neqv. .false.) then
is_prime = .true.
end if
end do
return
end function
END PROGRAM
So if you were to comment out the line I pointed out, the result of "mini" will be different than if you were to keep it, as I said.
I'm fairly new at fortran so I don't know wether I'm doing something wrong, or if this has something to do with the compiler, but it seems really weird to me that putting a print*, line would in any way change the value of the variabe, and that's what seems to happen.
For example if you try it yourselve, the output of mini when the print line is in, is for exaple,, typing in 48, is 29, which is right, it's the minimum prime number between 48 and ts half, but when you tipe in 48 and the famous print line is commented out, the output will be -2, instead of 29.
Any of you know why this happenes?
#francescalus is right, the logic of is_prime is wrong.
You can tell by checking the first result (the print *, is_prime(n)) of the program.
Below, a version with a correct is_prime. I first assign .true. to the result and invalidate it to .false. when the test is true.
PROGRAM hello
IMPLICIT NONE
integer :: n,i, mini
read*, n
print*, is_prime(n)
!!---------------------------------------------------------------------
do i=n, n/2, -1
print*, "I= ", i
if(is_prime(i)) then
mini = i
end if
end do
print*, "the lowest prime number between your number and its half is: ", mini
!!----------------------------------------------------------
CONTAINS
logical function is_prime(n)
integer, intent(in) :: n
integer :: i
is_prime = .true.
do i=2,n
if(mod(n,i) == 0 .and. (i/=1 .and. i/=n) ) then
is_prime = .false.
end if
end do
end function is_prime
END PROGRAM
EDIT: I should add that the issue with the influence of the print statement comes up from time to time. When it arises, it points to a flaw in the logic of the code that then becomes sensitive to situations of ill-defined results.

Fortran error common block

Where is the problem? Someone please give me the solution. Errors are:
WARNING - Common block "P/" was previously defined as size 128 but is now defined as size 1320
WARNING - Common block "P/" was previously defined as size 128 but is now defined as size 1320
I don't have any idea to solve it.
This is a mathematical problem solving program.
IMPLICIT REAL*8(A-H,O-Z)
COMMON/P/FW,AK,PR,GC,DA,XQ,SC,EC,DU,SR,RE,FS,XR,XK,RM1,GR
COMMON/V/IR,IX
COMMON/VV/G1,G2,G3
OPEN (1, FILE='MS99.dat',STATUS='UNKNOWN')
OPEN (2, FILE='MMS109.dat',STATUS='UNKNOWN')
FW=1.0
AK=1.0
GR=0.0
PR=10.0
GC=0.8
DA=1.0
XQ=1.0
SC=2.0
EC=2.0
DU=0.1
SR=0.1
RE=0.1
FS=0.5
XR=0.7
DU=0.9
XK=0.8
RM1= (1+(16/(3*XR)))
IR=80
IX=20
G1=0.0001
G2=0.0001
G3=0.0001
CALL DRFFO
CALL COMP1
1 FORMAT(2X,F6.2,2X,14F9.4)
2 FORMAT(2X,7(A6,F13.7))
CLOSE(1)
CLOSE(2)
STOP
END
C****************DERFO********************
SUBROUTINE DRFFO
IMPLICIT REAL*8(A-H,O-Z)
COMMON/P/FW,AK,PR,GC,DA,XQ,SC,EC,DU,SR,RE,FS,XR,XK,RM1,GR
COMMON/V/IR,IX
COMMON/VV/G1,G2,G3
DIMENSION XD(50),XK(3,50),X(50),F(50)
EXTERNAL DERFO
N=28
ITMAX=8
EPS=0.000001
KK=0
555 KK=KK+1
IF (KK.EQ.100)STOP
WRITE (*,*) 'IR=',IR
DO 101 ITER=1,IR
T=0.0
DO K=1,N
X(K)=0.0
ENDDO
X(1)=FW
X(2)=1.0
X(3)=G1
X(4)=1.0
X(5)=G2
X(6)=1.0
X(7)=G3
X(10)=1.0
X(18)=1.0
X(28)=1.0
H=0.01
DO I=1,IR
CALL RKSYS(DERFO,T,H,X,XD,XK,F,N)
DO K=1,N
X(K)=XD(K)
ENDDO
T=T+H
ENDDO
A11=X(9)**2+X(11)**2+X(13)**2+X(10)**2+X(12)**2+X(14)**2
A12=X(9)*X(16)+X(11)*X(18)+X(13)*X(20)+X(10)*X(17)+X(12)*X(19)
1 +X(14)*X(21)
A13=X(9)*X(23)+X(11)*X(25)+X(13)*X(27)+X(10)*X(24)+X(12)*X(26)
1 +X(14)*X(28)
A21=A12
A22=X(16)**2+X(18)**2+X(20)**2+X(17)**2+X(19)**2+X(21)**2
A23=X(16)*X(23)+X(18)*X(25)+X(20)*X(27)+X(17)*X(24)+X(19)*X(26)
1 +X(21)*X(28)
A31=A13
A32=A23
A33=X(23)**2+X(25)**2+X(27)**2+X(24)**2+X(26)**2+X(28)**2
B1=-(X(2)*X(9)+X(4)*X(11)+X(6)*X(13)+X(3)*X(10)+X(5)*X(12)
1 +X(7)*X(14))
B2=-(X(2)*X(16)+X(4)*X(18)+X(6)*X(20)+X(3)*X(17)+X(5)*X(19)
1 +X(7)*X(21))
B3=-(X(2)*X(23)+X(4)*X(25)+X(6)*X(27)+X(3)*X(24)+X(5)*X(26)
1 +X(7)*X(28))
ERR=X(2)**2+X(3)**2+X(4)**2+X(5)**2+X(6)**2+X(7)**2
WRITE(*,29)'G1=',G1,'G2=',G2,'G3=',G3,'ERR=',ERR
DG=(A11*(A22*A33-A23*A32)-A12*(A21*A33-A23*A31)+A13*(A21*A32-
1 A22*A31))
DG11=(B1*(A22*A33-A23*A32)-A12*(B2*A33-A23*B3)+A13*(B2*A32-A22*B3)
1 )
DG1=DG11/DG
DG22=(A11*(B2*A33-A23*B3)-B1*(A21*A33-A23*A31)+A13*(A21*B3-B2*A31)
1 )
DG2=DG22/DG
DG33=(A11*(A22*B3-B2*A32)-A12*(A21*B3-B2*A31)+B1*(A21*A32-A22*A31)
1 )
DG3=DG33/DG
IF(ERR.LT.EPS)GOTO 22
G1=G1+DG1
G2=G2+DG2
G3=G3+DG3
IF(ITER.GE.ITMAX)THEN
IR=IR+IX
GO TO 555
END IF
101 CONTINUE
22 WRITE (2,29)'ERR=',ERR,'G1=',G1,'G2=',1/G2,'G3='
1 ,-G3
29 FORMAT (2X,4(A6,F13.7))
RETURN
END SUBROUTINE
C**********************COMP1**************************
SUBROUTINE COMP1
IMPLICIT REAL*8(A-H,O-Z)
COMMON/P/FW,AK,PR,GC,DA,XQ,SC,EC,DU,SR,RE,FS,XR,XK,RM1,GR
COMMON/V/IR,IX
COMMON/VV/G1,G2,G3
DIMENSION XD(50),XK(3,50),F(50),X(50)
EXTERNAL DERFO
N=7
T=0.0
DO K=1,N
X(K)=0.0
ENDDO
X(1)=FW
X(2)=1.0
X(3)=G1
X(4)=1.0
X(5)=G2
X(6)=1.0
X(7)=G3
X(10)=1.0
X(18)=1.0
X(28)=1.0
H=0.01
WRITE(1,50)'eta','X(2)','g1','X(4)','g2','X(6)','g3'
WRITE(1,30)T,X(2),X(3),X(4),X(5),X(6),X(7)
DO I=1,IR
CALL RKSYS(DERFO,T,H,X,XD,XK,F,N)
DO K=1,N
X(K)=XD(K)
ENDDO
T=T+H
IF(I/5*5.EQ.I)THEN
WRITE(1,30)T,X(2),X(3),X(4),X(5),X(6),X(7)
ENDIF
ENDDO
50 FORMAT(A8,2X,A7,2X,A7,2X,A7,2X,A7,2X,A7,2X,A7)
30 FORMAT(2X,F6.2,2X,6F9.4)
RETURN
END
c*********************DERFO************************
SUBROUTINE DERFO(X,T,F,N)
IMPLICIT REAL*8(A-H,O-Z)
COMMON/P/FW,AK,PR,GC,DA,XQ,SC,EC,DU,SR,RE,FS,XR,XK,RM1,GR
DIMENSION X(N),F(N)
C PI=4.*ATAN(1.0)
F(1)=X(2)
F(2)=X(3)
F(3)=(FS/DA)*X(2)*X(2)+(X(1)/(DA*RE))+AK*X(1)-GC*X(6)-GR*X(4)-X(1)
1 *X(3)
F(10)=(FS/DA)*2*X(2)*X(9)+X(8)/(DA*RE)+AK*X(8)-GC*X(13)-GR*X(11)-
1 X(1)*X(10)-X(3)*X(8)
F(17)=(FS/DA)*2*X(2)*X(16)+X(15)/(DA*RE)+AK*X(15)-GC*X(20)-GR*
1 X(18)-X(1)*X(17)-X(3)*X(15)
F(24)=(FS/DA)*2*X(2)*X(23)+X(22)/(DA*RE)+AK*X(22)-GC*X(27)-GR*
1 X(25)-X(1)*X(24)-X(3)*X(22)
F(4)=X(5)
F(5)=(-1*(PR*X(1)*X(5)+PR*DU*F(7)+PR*XQ*X(4)+PR*EC*X(3)*X(3))/RM1)
F(12)=(-1*(PR*X(1)*X(12)+PR*X(5)*X(8)+PR*DU*F(14)+PR*XQ*X(11)+PR*
1 EC*2*X(3)*X(10))/RM1)
F(19)=(-(PR*X(1)*X(19)+PR*X(5)*X(15)+PR*DU*F(21)+PR*XQ*X(18)+PR*
1 EC*2*X(3)*X(17))/RM1)
F(26)=(-(PR*X(1)*X(26)+PR*X(5)*X(22)+PR*DU*F(28)+PR*XQ*X(25)+PR*
1 EC*2*X(3)*X(24))/RM1)
F(6)=X(7)
F(7)=XK*X(6)-SC*X(1)*X(7)-SC*SR*F(5)
F(8)=X(9)
F(9)=X(10)
F(11)=X(12)
F(13)=X(14)
F(14)=XK*X(13)-SC*X(1)*X(14)-SC*X(7)*X(8)-SC*SR*F(12)
F(15)=X(16)
F(16)=X(17)
F(18)=X(19)
F(20)=X(21)
F(21)=XK*X(20)-SC*X(1)*X(21)-SC*X(7)*X(15)-SC*SR*F(19)
F(22)=X(23)
F(23)=X(24)
F(25)=X(26)
F(27)=X(28)
F(28)=XK*X(27)-SC*X(1)*X(28)-SC*X(7)*X(22)-SC*SR*F(26)
RETURN
END
C******************IMPLICIT R-K SIXTH ORDER METHOD*******************
SUBROUTINE RKSYS(DERIVS,T,H,X,XD,XK,F,N)
IMPLICIT REAL*8(A-H,O-Z)
DIMENSION X(N),XD(N),XK(4,N),F(N)
SQT=SQRT(15.0)
A1=(5.-SQT)/10.0
A2=1.0/2.0
A3=(5.+SQT)/10.0
B1=5.0/36.0
B2=(10.0-3.0*SQT)/45.0
B3=(25.0-6.0*SQT)/180.0
C1=(10.0+3.0*SQT)/72.0
C2=2.0/9.0
C3=(12.0-3.0*SQT)/72.0
D1=(25.0+6.0*SQT)/180.0
D2=(10.0+3.0*SQT)/45.0
D3=5.0/36.0
CALL DERIVS(X,T,F,N)
DO I=1,N
XK(1,I)=H*F(I)
XK(2,I)=H*F(I)
XK(3,I)=H*F(I)
XD(I)=X(I)+B1*XK(1,I)+B2*XK(2,I)+B3*XK(3,I)
ENDDO
CALL DERIVS(XD,T+A1*H,F,N)
DO I=1,N
XK(1,I)=H*F(I)
XD(I)=X(I)+C1*XK(1,I)+C2*XK(2,I)+C3*XK(3,I)
ENDDO
CALL DERIVS(XD,T+A2*H,F,N)
DO I=1,N
XK(2,I)=H*F(I)
XD(I)=X(I)+D1*XK(1,I)+D2*XK(2,I)+D3*XK(3,I)
ENDDO
CALL DERIVS(XD,T+A3*H,F,N)
DO I=1,N
XK(3,I)=H*F(I)
XD(I)=X(I)+(5.0*XK(1,I)+8.0*XK(2,I)+5.0*XK(3,I))/18.0
ENDDO
RETURN
END
It is just a warning and they can be normally be ignored but this is not advised. The common block /P/ has an element XK:
COMMON/P/FW,AK,PR,GC,DA,XQ,SC,EC,DU,SR,RE,FS,XR,XK,RM1,GR
in the main program it does not get a size/ dimension and is a scalar. In the subroutines it gets a size XK(3,50):
DIMENSION XD(50),XK(3,50),X(50),F(50)
and thus is and array with 150 elements (i.e. 1200 bytes).
It is advised that the DIMENSION statement is also placed in the main program.
As a side note, I hope you didn't write the code as it is very old fashioned (normally one would use modules etc. for the variables in this case).

least squares minimisation fortran 77

Trying to get a one-parameter least squares minimisation working in fortran77. Here's the code; it compiles and seems to work except....it gets caught in an infinite loop between values of h1= 1.8E-2 and 3.5E-2.
Having a look now but, odds are, I'm not going to have much luck sussing the issue on my own. All help welcome!
PROGRAM assignment
! A program designed to fit experiemental data, using the method
! of least squares to minimise the associated chi-squared and
! obtain the four control parameters A,B,h1 and h2.
!*****************************************************************
IMPLICIT NONE
INTEGER i
DOUBLE PRECISION t(17),Ct(17),eCt(17)
DOUBLE PRECISION h1loop1,h1loop2,deltah,Cs
DOUBLE PRECISION chisqa,chisqb,dchisq
OPEN(21, FILE='data.txt', FORM='FORMATTED', STATUS='OLD')
DO i=1,17
READ(21,*)t(i),Ct(i),eCt(i)
END DO
CLOSE(21)
!Read in data.txt as three one dimensional arrays.
!*****************************************************************
!OPEN(21, FILE='outtest.txt', FORM='FORMATTED', STATUS='NEW')
!DO i=1,17
! WRITE(21,*)t(i),Ct(i),eCt(i)
!END DO
!CLOSE(21)
!
!Just to check input file is being read correctly.
!*****************************************************************
!**********************Minimising Lamda1 (h1)*********************
deltah= 0.0001
h1loop2= 0.001
h1loop1= 0.0 !Use initial value of 0 to calculate start-point chisq
DO 10
chisqa= 0.0
DO 20 i= 1, 17
Cs= exp(-h1loop1*t(i))
chisqa= chisqa + ((Ct(i) - Cs)/eCt(i))**2
20 END DO
chisqb= 0.0
DO 30 i= 1, 17
h1loop2= h1loop2 + deltah
Cs= exp(-h1loop2*t(i))
chisqb= chisqb + ((Ct(i) - Cs)/eCt(i))**2
30 END DO
!Print the two calculated chisq values to screen.
WRITE(6,*) 'Chi-squared a=',chisqa,'for Lamda1=',h1loop1
WRITE(6,*) 'Chi-squared b=',chisqb,'for Lamda1=',h1loop2
dchisq= chisqa - chisqb
IF (dchisq.GT.0.0) THEN
h1loop1= h1loop2
ELSE
deltah= deltah - ((deltah*2)/100)
END IF
IF (chisqb.LE.6618.681) EXIT
10 END DO
WRITE(6,*) 'Chi-squared is', chisqb,' for Lamda1 = ', h1loop2
END PROGRAM assignment
EDIT: Having looked at it again I've decided I have no clue what's screwing it up. Should be getting a chi-squared of 6618.681 from this, but it's just stuck between 6921.866 and 6920.031. Help!
do i=1
is not starting a loop, for a loop you need to specify an upper bound as well:
do i=1,ub
that's why you get the error message about the doi not having a type, in fixed format spaces are insignificant...
Edit: If you want to have an infinite loop, just skip the "i=" declaration completely. You can use an exit statement to leave the loop, when a certain criterion has been reached:
do
if (min_reached) EXIT
end do
Edit2: I don't know why you stick to F77 fixed format. Here is your program in free format, with some fixes of places, which looked weird, without digging too much into the details:
PROGRAM assignment
! A program designed to fit experiemental data, using the method
! of least squares to minimise the associated chi-squared and
! obtain the four control parameters A,B,h1 and h2.
!*****************************************************************
IMPLICIT NONE
integer, parameter :: rk = selected_real_kind(15)
integer, parameter :: nd = 17
integer :: i,t0
real(kind=rk) :: t(nd),t2(nd),Ct(nd),eCt(nd),Ctdiff(nd),c(nd)
real(kind=rk) :: Aa,Ab,Ba,Bb,h1a,h1b,h2a,h2b,chisqa,chisqb,dchisq
real(kind=rk) :: deltah,Cs(nd)
OPEN(21, FILE='data.txt', FORM='FORMATTED', STATUS='OLD')
DO i=1,nd
READ(21,*) t(i),Ct(i),eCt(i)
END DO
CLOSE(21)
!Read in data.txt as three one dimensional arrays.
!*****************************************************************
!OPEN(21, FILE='outtest.txt', FORM='FORMATTED', STATUS='NEW')
!DO i=1,17
! WRITE(21,*)t(i),Ct(i),eCt(i)
!END DO
!CLOSE(21)
!
!Just to check input file is being read correctly.
!*****************************************************************
!****************************Parameters***************************
Aa= 0
Ba= 0
h1a= 0
h2a= 0
!**********************Minimising Lamda1 (h1)*********************
deltah= 0.001_rk
h1b= deltah
minloop: DO
chisqa= 0
DO i= 1,nd
Cs(i)= exp(-h1a*t(i))!*Aa !+ Ba*exp(-h2a*t(i))
Ctdiff(i)= Ct(i) - Cs(i)
c(i)= Ctdiff(i)**2/eCt(i)**2
chisqa= chisqa + c(i)
h1a= h1a + deltah
END DO
! Use initial h1 value of 0 to calculate start-point chisq.
chisqb= 0
DO i= 1,nd
h1b= h1b + deltah
Cs(i)= exp(-h1b*t(i))!*Ab !+ Bb*exp(-h2b*t(i))
Ctdiff(i)= Ct(i) - Cs(i)
c(i)= Ctdiff(i)**2/eCt(i)**2
chisqb= chisqb + c(i)
END DO
! First-step h1 used to find competing chisq for comparison.
WRITE(6,*) 'Chi-squared a=', chisqa,'for Lamda1=',h1a
WRITE(6,*) 'Chi-squared b=', chisqb,'for Lamda1=',h1b
! Prints the two calculated chisq values to screen.
dchisq= chisqa - chisqb
IF (dchisq.GT.0) THEN
h1a= h1b
ELSE IF (dchisq.LE.0) THEN
deltah= (-deltah*2)/10
END IF
IF (chisqb.LE.6000) EXIT minloop
END DO minloop
WRITE(6,*) 'Chi-squared is', chisqb,'for Lamda1=',h1b
END PROGRAM assignment

Is there a standard way to check for Infinite and NaN in Fortran 90/95?

I've been trying to find a standards-compliant way to check for Infinite and NaN values in Fortran 90/95 but it proved harder than I thought.
I tried to manually create Inf and NaN variables using the binary representation described in IEEE 754, but I found no such functionality.
I am aware of the intrinsic ieee_arithmetic module in Fortran 2003 with the ieee_is_nan() and ieee_is_finite() intrinsic functions. However it's not supported by all the compilers (notably gfortran as of version 4.9).
Defining infinity and NaN at the beginning like pinf = 1. / 0 and nan = 0. / 0 seems hackish to me and IMHO can raise some building problems - for example if some compilers check this in compile time one would have to provide a special flag.
Is there a way I can implement in standard Fortran 90/95?
function isinf(x)
! Returns .true. if x is infinity, .false. otherwise
...
end function isinf
and isnan()?
The simple way without using the ieee_arithmatic is to do the following.
Infinity: Define your variable infinity = HUGE(dbl_prec_var) (or, if you have it, a quad precision variable). Then you can simply check to see if your variable is infinity by if(my_var > infinity).
NAN: This is even easier. By definition, NAN is not equal to anything, even itself. Simply compare the variable to itself: if(my_var /= my_var).
I don't have enough rep to comment so I'll "answer" regarding Rick Thompson's suggestion for testing infinity.
if (A-1 .eq. A)
This will also be true if A is a very large floating point number, and 1 is below the precision of A.
A simple test:
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
outputs:
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!!!
No.
The salient parts of IEEE_ARITHMETIC for generating/checking for NaN's are easy enough to write for gfortran for a particular architecture.
I have used:
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
This will print 'Got a problem' for number = 0.0D0, 1.0D0/0.0D0, 0.0D0/0.0D0, SQRT(-2.0D0), and also for overflows and underflows such as number = EXP(1.0D800) or number = EXP(-1.0D800). Notice that generally, things like number = EXP(1.0D-800) will just set number = 1.0 and produce a warning at compilation time, but the program will print 'We are OK', which I find acceptable.
OL.
for testing NaN none of the things worked eg.if testing real s2p to see if it is NaN then
if(isnan(s2p))
did not work in gfortran nor did
if(s2p.ne.s2p).
The only thing that worked was
if(.not.s2p<1.and..not.s2p>1)
though to make real sure u may want to add
if(.not.s2p<1.and..not.s2p>1.and..not.s2p==1)
No.
Neither is there a standards-compliant way of checking for infinities or NaNs in Fortran 90/95, nor can there be a standards-compliant way. There is no standards-compliant way of defining either of these quasi-numbers in Fortran 90/95.
For Fortran, 1/infinity=0
thus, divide your variable by zero
i.e
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
there's your infinity check. No complication necessary.
For Inf it seems to work that if (A-1 .eq. A) is true, then A is Inf