Logarithm of 0 causes error even in an unreachable if condition - if-statement

I implemented the following code in Fortran 90, where I want a parameter tau to be calculated using logarithms of some parameters, only if these are within appropriate ranges.
MODULE nrtype
INTEGER, PARAMETER :: SP=KIND(1.0)
INTEGER, PARAMETER :: DP=KIND(1.0d0)
INTEGER, PARAMETER :: I4B=SELECTED_INT_KIND(9)
INTEGER, PARAMETER :: I2B=SELECTED_INT_KIND(4)
INTEGER, PARAMETER :: I1B=SELECTED_INT_KIND(2)
INTEGER, PARAMETER :: SPC=KIND((1.0,1.0))
INTEGER, PARAMETER :: DPC=KIND((1.0D0,1.0D0))
INTEGER, PARAMETER :: LGT=KIND(.TRUE.)
END MODULE
MODULE parameters
USE nrtype
REAL(DP), PARAMETER :: beta=.98_dp
REAL(DP), PARAMETER :: maxtol=1.0e-6_dp
REAL(DP), PARAMETER :: theta=1.0_dp
REAL(DP), PARAMETER :: delta=0.0_dp
END MODULE
PROGRAM mainp
USE parameters
USE nrtype
IMPLICIT NONE
INTEGER(I4B) :: tau
REAL(DP) :: taustar
IF (theta > 1.0_dp .AND. (delta > 0.0_dp .AND. delta < 1.0_dp)) THEN
taustar=LOG(maxtol/(beta*(1.0_dp-delta)*(theta-1.0_dp)))/LOG(beta*delta)
tau=CEILING(taustar,REAL(DP))
ENDIF
IF (theta > 1.0_dp .AND. delta==0.0_dp) THEN
tau=1
ELSEIF (theta == 1.0_DP .OR. delta==1.0_DP) THEN
tau=0
ENDIF
END PROGRAM main
However, when compiling using gfortran 6.1 in a MacBook Air 2013 with OSX El Capitan, I get the following error:
program.f90:30:69:
taustar=LOG(maxtol/(beta*(1.0_dp-delta)*(theta-1.0_dp)))/LOG(beta*delta)
1
Error: Argument of LOG at (1) cannot be less than or equal to zero
What mistake am I doing on the code? It looks as if the IF statement is not being recognised.

The expression LOG(beta*delta) is considered invalid by gfortran when delta is 0 constant. It doesn't matter that it is in an unreachable part of code. It is invalid. You can't just put it in an if condition or anywhere else.
A solution might be to not declare delta as parameter or to use some preprocessor. Other compilers might accept it (I tried ifort). I am not sure about the standard.

(Though this is something like a long comment...) gfortran-6.1 on Mac OSX10.9 gave the following information when compiled with -fdump-fortran-original or -fdump-fortran-optimized:
code:
IF .false.
ASSIGN mainp:taustar (/ log[(((/ 9.9999999999999995e-7_8
(parens (* (* 9.7999999999999998e-1_8
(parens 1.0000000000000000_8))
(parens 0_8))))))] log[((0_8))])
ASSIGN mainp:tau ceiling[((mainp:taustar) (8.00000000))]
ENDIF
IF .false.
ASSIGN mainp:tau 1 ELSE
IF .true.
ASSIGN mainp:tau 0
ENDIF
ENDIF
The result was the same for all -O0, -O2, -O3, and -O5.
ifort-14.0 compiled the program without complaining the unreachable log line (while complaining about tau=CEILING(...)). The third IF block corresponding to theta == 1.0_DP .OR. delta==1.0_DP was executed.
Oracle fortran 12.4 was a bit interesting because it gave a warning like this:
taustar=LOG(maxtol/(beta*(1.0_dp-delta)*(theta-1.0_dp)))/LOG(beta*delta)
^ ^ ^
"test.f90", Line = 31, Column = 27: WARNING: A divisor of zero was detected in an expression.
"test.f90", Line = 31, Column = 65: WARNING: Evaluation of this constant expression produced a NaN or other abnormal value.
"test.f90", Line = 31, Column = 74: WARNING: The argument is not in the valid range for this intrinsic.
but again the third IF block was executed.
Also, if I declared delta as a usual variable (not with the PARAMETER attribute), gfortran also executed the third IF block after removing the CEILING(...) (this line seems problematic for a different reason).
A workaround may be to assign the constants to local variables once and pass them to LOG(...)/LOG(...) (in a sense, to cheat gfortran!):
REAL(DP) :: arg1, arg2, tmp
IF (theta > 1.0_dp .AND. (delta > 0.0_dp .AND. delta < 1.0_dp)) THEN
tmp = beta * (1.0_dp - delta) * (theta - 1.0_dp)
arg1 = maxtol / tmp
arg2 = beta * delta
taustar = LOG( arg1 ) / LOG( arg2 )
ENDIF
This seems to work when theta and delta have the above corner-case values and give correct results for other cases. In the former case, the output of gfortran -fdump-fortran-original becomes like this:
code:
IF .false.
ASSIGN mainp:tmp 0_8
ASSIGN mainp:arg1 (/ 9.9999999999999995e-7_8 mainp:tmp)
ASSIGN mainp:arg2 0_8
ASSIGN mainp:taustar (/ __log_r8[[((mainp:arg1))]] __log_r8[[((mainp:arg2))]])
ENDIF

This error is being thrown at compile time, not run-time.
Since beta and delta are constants, the compiler is taking a shortcut and evaluating the log before the program runs. Since it is a log of zero, it is throwing an error, as it should.
I'm not sure what you are trying to do. The compiler is right, this will always be a log of zero. Are you sure you want delta to be a constant?

Related

How do I define integer array for given variable nBoxes [duplicate]

I'm writing a code for LU decomposition and I don't know how to fix the "unexpected data declaration statement" pointed at line 8 (where I'm declaring an array. See the code fragment). Why is it unexpected?
!Decomposição LU
!-----------------------------------------------------------
PROGRAM LUdecomp
IMPLICIT INTEGER (I-K,N), REAL (A-H, L-M,O-Z)
INTEGER, PARAMETER :: N=3
REAL, DIMENSION (N,N) :: A,L,U
A = reshape((/3.,1.,4.,4.,2.,0.,3.,2.,3./),(/3,3/)) !exemplo do Bortoli*******
REAL, DIMENSION(3) :: B=(/9.,3.,-2./),Z,X
OPEN(1,file = 'LUFACTOR.out')
!
! FORALL (I = 1:N, J = 1:N) A(I,J) = 1.0/REAL(I+J-1)
!-------Fazendo a fatoração A = LU-----------------------------
CALL LU(N, A, L, U)
DO I=1,N
WRITE(*,10)(L(I,J), J=1,N), (U(I,J), J=1,N)
END DO
10 FORMAT(3(F8.4), 7x, 3(F8.4))
!
This statement
REAL, DIMENSION(3) :: B=(/9.,3.,-2./),Z,X
is in the wrong place. In a Fortran program-unit (program, subroutine, function) -- certainly one without the new ASSOCIATE and BLOCK constructs -- all declarations have to precede all executable statements.
Move the misplaced statement ahead of the first executable statement.

My code gives me random numbers around 10^-38 but I'm not using any random functions

I use Fortran 90 via Force 2.0, with a 64bits pc under windows 10.
I believe it may be a bug since my classmates use a very similar code and it works for them.
This is my code :
program integ
implicit none
real :: a_x , b_x , integ_1d, c
a_x = 0
b_x = 1
c = integ_1d(a_x,b_x)
write(*,*)c
pause
end program integ
real function integ_1d (a_x , b_x)
real :: x, f_x, pas
real :: inte, a_x, b_x
integer :: i
integer , parameter :: npas=100
pas=(b_x-a_x )/ npas
inte =0.E0
do i=0,npas-1
x=a_x+( i*pas )
inte=inte+ f_x
end do
integ_1d=inte*pas
end function integ_1d
real function f_x(x)
real :: x
f_x = x*x
end function f_x
It compiles without any issues but always gives me different values, around 10^-38. example :
1.75483065E-38
PAUSE
To resume execution, type go. Other input will terminate the job.
or
1.16708418E-38
PAUSE
To resume execution, type go. Other input will terminate the job.
with the exact same code, compiled on the same computer with the same fortran version.
Thank you for your time.

Dummy argument not agreeing with actual argument when passing function

I'm trying to implement Newton's method but I'm getting a confusing error message. In my code you'll see I called external with f1 and f2 which I assumes tells the computer to look for the function but it's treating them as variables based on the error message. I've read the stack overflow posts similar to my issue but none of the solutions seem to work. I've tried with and without the external but the issue still persists. Hoping someone could see what I'm missing.
implicit none
contains
subroutine solve(f1,f2,x0,n, EPSILON)
implicit none
real(kind = 2), external:: f1, f2
real (kind = 2), intent(in):: x0, EPSILON
real (kind = 2):: x
integer, intent(in):: n
integer:: iteration
x = x0
do while (abs(f1(x))>EPSILON)
iteration = iteration + 1
print*, iteration, x, f1(x)
x = x - (f1(x)/f2(x))
if (iteration >= n) then
print*, "No Convergence"
stop
end if
end do
print*, iteration, x
end subroutine solve
end module newton
Program Lab10
use newton
implicit none
integer, parameter :: n = 1000 ! maximum iteration
real(kind = 2), parameter :: EPSILON = 1.d-3
real(kind = 2):: x0, x
x0 = 3.0d0
call solve(f(x),fp(x),x0,n, EPSILON)
contains
real (kind = 2) function f(x) ! this is f(x)
implicit none
real (kind = 2), intent(in)::x
f = x**2.0d0-1.0d0
end function f
real (kind = 2) function fp(x) ! This is f'(x)
implicit none
real (kind = 2), intent(in)::x
fp = 2.0d0*x
end function fp
end program Lab10```
You seem to be passing function results to your subroutine and not the functions themselves. Remove (x) when calling solve() and the problem will be resolved. But more importantly, this code is a prime example of how to not program in Fortran. The attribute external is deprecated and you better provide an explicit interface. In addition, what is the meaning of kind = 2. Gfortran does not even comprehend it. Even if it comprehends the kind, it is not portable. Here is a correct portable modern implementation of the code,
module newton
use iso_fortran_env, only: RK => real64
implicit none
abstract interface
pure function f_proc(x) result(result)
import RK
real(RK), intent(in) :: x
real(RK) :: result
end function f_proc
end interface
contains
subroutine solve(f1,f2,x0,n, EPSILON)
procedure(f_proc) :: f1, f2
real(RK), intent(in) :: x0, EPSILON
integer, intent(in) :: n
real(RK) :: x
integer :: iteration
x = x0
do while (abs(f1(x))>EPSILON)
iteration = iteration + 1
print*, iteration, x, f1(x)
x = x - (f1(x)/f2(x))
if (iteration >= n) then
print*, "No Convergence"
stop
end if
end do
print*, iteration, x
end subroutine solve
end module newton
Program Lab10
use newton
integer, parameter :: n = 1000 ! maximum iteration
real(RK), parameter :: EPSILON = 1.e-3_RK
real(RK) :: x0, x
x0 = 3._RK
call solve(f,fp,x0,n, EPSILON)
contains
pure function f(x) result(result) ! this is f(x)
real (RK), intent(in) :: x
real (RK) :: result
result = x**2 - 1._RK
end function f
pure function fp(x) result(result) ! This is f'(x)
real (RK), intent(in) :: x
real (RK) :: result
result = 2 * x
end function fp
end program Lab10
If you expect to pass nonpure functions to the subroutine solve(), then remove the pure attribute. Note the use of real64 to declare 64-bit (double precision) real kind. Also notice how I have used _RK suffix to assign 64-bit precision to real constants. Also, notice I changed the exponents from real to integer as it is multiplication is more efficient than exponentiation computationally. I hope this answer serves more than merely the solution to Lab10.

Unclassifiable statement at (1) when calling a function

I'm relatively new to Fortran and I have an assignment to find quadrature weights and points where the points are the zeros of the nth legendre polynomial (found using Newton's method); I made functions to find the value of Pn(x) and P'n(x) to sub into Newton's method.
However when actually using the functions in my quadrature subroutine it comes back with:
Coursework2a.f90:44.3:
x = x - P(n,x)/dP(n,x)
1
Error: Unclassifiable statement at (1)
Does anybody know any reasons why this statement could be classed as unclassifiable?
subroutine Quadrature(n)
implicit none
integer, parameter :: dpr = selected_real_kind(15) !Double precision
real(dpr) :: P, dP, x, x_new, error = 1, tolerance = 1.0E-6, Pi = 3.141592 !Define Variables
integer, intent(in) :: n
integer :: i
!Next, find n roots. Start with first guess then iterate until error is greater than some tolerance.
do i = 1,n
x = -cos(((2.0*real(i)-1.0)/2.0*real(n))*Pi)
do while (error > tolerance)
x_new = x
x = x - P(n,x)/dP(n,x)
error = abs(x_new-x)
end do
print *, x
end do
end subroutine Quadrature
The line
x = -cos(((2.0*real(i)-1.0)/2.0*real(n))*Pi)
is likely missing a set of brackets around the denominator. As it is, the line divides (2.0*real(i)-1.0) by 2.0, then multiplies the whole thing by real(n). This may be why you get the same root for each loop.
real function p(n,x)
real::n,x
p=2*x**3 !or put in the function given to you.
end function
real function dp(n,x)
real::n,x
dp=6*x**2 !you mean derivative of polynomial p, I guess.
end function
Define function like this separately outside the main program. Inside the main program declare the functions like:
real,external::p, dp

Unexpected data declaration statement

I'm writing a code for LU decomposition and I don't know how to fix the "unexpected data declaration statement" pointed at line 8 (where I'm declaring an array. See the code fragment). Why is it unexpected?
!Decomposição LU
!-----------------------------------------------------------
PROGRAM LUdecomp
IMPLICIT INTEGER (I-K,N), REAL (A-H, L-M,O-Z)
INTEGER, PARAMETER :: N=3
REAL, DIMENSION (N,N) :: A,L,U
A = reshape((/3.,1.,4.,4.,2.,0.,3.,2.,3./),(/3,3/)) !exemplo do Bortoli*******
REAL, DIMENSION(3) :: B=(/9.,3.,-2./),Z,X
OPEN(1,file = 'LUFACTOR.out')
!
! FORALL (I = 1:N, J = 1:N) A(I,J) = 1.0/REAL(I+J-1)
!-------Fazendo a fatoração A = LU-----------------------------
CALL LU(N, A, L, U)
DO I=1,N
WRITE(*,10)(L(I,J), J=1,N), (U(I,J), J=1,N)
END DO
10 FORMAT(3(F8.4), 7x, 3(F8.4))
!
This statement
REAL, DIMENSION(3) :: B=(/9.,3.,-2./),Z,X
is in the wrong place. In a Fortran program-unit (program, subroutine, function) -- certainly one without the new ASSOCIATE and BLOCK constructs -- all declarations have to precede all executable statements.
Move the misplaced statement ahead of the first executable statement.