FORTRAN logic notproblem - fortran

If I just use my function once, it works properly. If I make it do a loop like down below, the four lines of commented code, my code malfunctions. I can't really figure out why it will always return T or F for every other number after the initial value.
Asterisks are in the parenthesis of WRITE and READ but it doesn't show up here for some reason.
PROGRAM PRIME
INTEGER :: N = 0, i = 1,x = 0
LOGICAL :: IP
WRITE (*,*) "Enter a number:"
READ (*,*) N
!DO WHILE ( N < 1000)
IP = IsPrime(N)
WRITE (*,*) IP, N
!N = N + 1
!END DO
read(*,*) x
CONTAINS
FUNCTION IsPrime(N)
LOGICAL :: IsPrime
INTEGER, INTENT(IN) :: N
IsPrime = .TRUE.
IF (N == 2) THEN
WRITE (*,*) N
ELSE
DO WHILE (i <= (N/2))
i = i + 2
IF (mod(N,i) == 0) THEN
IsPrime = .FALSE.
END IF
END DO
END IF
RETURN
END FUNCTION IsPrime
END PROGRAM PRIME

You're forgetting to reset i to 1 during each call to IsPrime.
The first time IsPrime is called, i=1 from the top of program main. However, i is incremented during the first IsPrime call to something other than 1 so the second call starts with i/=0.
Note that because IsPrime is contained within program main, IsPrime inherits i from program main.
I'm also bound to remind you to use implicit none everywhere to avoid other errors, although it's not a problem in this case.

Related

Getting the prime numbers till 10000 in fortran?

Im trying to print prime numbers till 10000. (display the first five for testing)
This is my program
program primes
implicit none
integer :: array(1229)
integer :: i, ind
logical :: is_prime
ind = 1
do i = 2, 10000, 1
if (is_prime(i) .eqv. .true.) then
array(ind) = i
ind = ind + 1
end if
end do
print *, array(1)
print *, array(2)
print *, array(3)
print *, array(4)
print *, array(5)
end program primes
function is_prime(n) result(ispr)
implicit none
integer :: c, i
integer, intent(in) :: n
logical :: ispr
c = 0
do i = 2, n
if (mod(i,2) == 0) then
c = c + 1
end if
end do
ispr = (c == 0)
end function is_prime
I don't know why but this is the output
9175178
6417360
5374044
6750309
7536745
Why does this happen and how to correct?
is_prime should be(n is the only divider of n besides 1 <=> c == 1)
function is_prime(n) result(ispr)
implicit none
integer :: c, i
integer, intent(in) :: n
logical :: ispr
c = 0
do i = 2, n
if (mod(n,i) == 0) then
c = c + 1
end if
end do
ispr = (c == 1)
end function is_prime
Could be optimezed by leaving the loop when c == 1 and i < n(after adding 1 to c)...
See on online fortran compiler
version with exit loop
While I am not familiar with modern Fortran, it looks to me as if function is_prime(n) result(ispr) is not working.
In the do loop in that function, you want a loop that tests thus:
is n divisible by 2?
is n divisible by 3?
is n divisible by 4?
is n divisible by 5?
and so on.
But, what it is actually doing is asking these:
is 2 divisible by 2?
is 3 divisible by 2?
is 4 divisible by 2?
is 5 divisible by 2?
and so on.
As a result, your counter will always have a non-zero value, and your function will always return false.
But, that's not the only problem. From your results, it looks like your Fortran implementation does not automatically initialize variables. Suppose I have statements like the following:
integer :: b
print *,b
What will be the result?
Remember, the names of variables represent locations in the computer's memory. If a variable is not initialized, it's value will be what was in the memory location before your program started to run. This value will not be related to your program.
I have 2 suggestions to fix the 2nd problem:
Prior to do i = 2, 10000, 1, have another loop that sets each value in array.
Set a values of each array (i) inside your do i = 2, 10000, 1 loop. One way to do this is to set one value when (is_prime(i) .eqv. .true.) is true and a different value when it is false.

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.

Big integer factorial function in Fortran, as efficient as python or Haskell

Here's my factorial function in Fortran.
module facmod
implicit none
contains
function factorial (n) result (fac)
use FMZM
integer, intent(in) :: n
integer :: i
type(IM) :: fac
fac = 1
if(n==0) then
fac = 1
elseif(n==1) then
fac = 1
elseif(n==2) then
fac = 2
elseif(n < 0) then
write(*,*) 'Error in factorial N=', n
stop 1
else
do i = 1, n
fac = fac * i
enddo
endif
end function factorial
end module facmod
program main
use FMZM
use facmod, only: factorial
implicit none
type(IM) :: res
integer :: n, lenr
character (len=:), allocatable :: str
character(len=1024) :: fmat
print*,'enter the value of n'
read*, n
res = factorial(n)
lenr = log10(TO_FM(res))+2
allocate(character(len=lenr) :: str)
write (fmat, "(A5,I0)") "i", lenr
call im_form(fmat, res, str)
print*, trim( adjustl(str))
end program main
I compile using FMZM:
gfortran -std=f2008 fac.F90 fmlib.a -o fac
echo -e "1000" | .fac computes easy. However, if I give this echo -e "3600" | .fac, I already get an error on my machine:
Error in FM. More than 200000 type (FM), (ZM), (IM) numbers
have been defined. Variable SIZE_OF_START in file
FMSAVE.f95 defines this value.
Possible causes of this error and remedies:
(1) Make sure all subroutines (also functions that do not
return type FM, ZM, or IM function values) have
CALL FM_ENTER_USER_ROUTINE
at the start and
CALL FM_EXIT_USER_ROUTINE
at the end and before any other return, and all
functions returning an FM, ZM, or IM function value have
CALL FM_ENTER_USER_FUNCTION(F)
at the start and
CALL FM_EXIT_USER_FUNCTION(F)
at the end and before any other return, where the actual
function name replaces F above.
Otherwise that routine could be leaking memory, and
worse, could get wrong results because of deleting some
FM, ZM, or IM temporary variables too soon.
(2) Make sure all subroutines and functions declare any
local type FM, ZM, or IM variables as saved. Otherwise
some compilers create new instances of those variables
with each call, leaking memory.
For example:
SUBROUTINE SUB(A,B,C,X,Y,RESULT)
TYPE (FM) :: A,B,C,X,Y,RESULT,ERR,TOL,H
Here A,B,C,X,Y,RESULT are the input variables and
ERR,TOL,H are local variables. The fix is:
SUBROUTINE SUB(A,B,C,X,Y,RESULT)
TYPE (FM) :: A,B,C,X,Y,RESULT
TYPE (FM), SAVE :: ERR,TOL,H
(3) Since = assignments for multiple precision variables are
the trigger for cleaning up temporary multiple precision
variables, a loop with subroutine calls that has no =
assignments can run out of space to store temporaries.
For example:
DO J = 1, N
CALL SUB(A,B,C,TO_FM(0),TO_FM(1),RESULT)
ENDDO
Most compilers will create two temporary variables with
each call, to hold the TO_FM values.
One fix is to put an assignment into the loop:
DO J = 1, N
ZERO = TO_FM(0)
CALL SUB(A,B,C,ZERO,TO_FM(1),RESULT)
ENDDO
(4) If a routine uses allocatable type FM, ZM, or IM arrays
and allocates and deallocates with each call, then after
many calls this limit on number of variables could be
exceeded, since new FM variable index numbers are
generated for each call to the routine.
A fix for this is to call FM_DEALLOCATE before actually
deallocating each array, so those index numbers can be
re-used. For example:
DEALLOCATE(T)
becomes:
CALL FM_DEALLOCATE(T)
DEALLOCATE(T)
(5) If none of this helps, try running this program again
after increasing the value of SIZE_OF_START and
re-compiling.
What optimizations or Fortran idioms am I missing that is hurting my performance so much?
For example, in python, I can factorial numbers much larger than 3500:
>>> import math
>>> math.factorial(100000)
Or in Haskell:
Prelude> product [1..100000]
Both these compute, not exactly quickly, but without error.
How can I improve my algorithm or better use existing libraries to improve performance of large integer factorials in Fortran? Is there a more appropriate big integer library than FMZM?
Try this. Apart from minor cosmetic changes, I just followed the recommendations of the error message in your question:
added calls to FM_ENTER_USER_FUNCTION and FM_EXIT_USER_FUNCTION,
added an assignment inside the loop (without this ii = to_im(i), it still fails, but I'm not sure why, as there is already an assignment with fac = fac * i, and accordind to the doc the assignment triggers cleaning up temporaries),
renamed factorial in main program as there is already a function with this name in FMZM.
Tested with ifort and n=100000.
module fac_mod
implicit none
contains
function factorial(n) result(fac)
use FMZM
integer, intent(in) :: n
integer :: i
type(IM) :: fac
type(IM), save :: ii
call FM_ENTER_USER_FUNCTION(fac)
fac = to_im(1)
if (n < 0) then
write (*, *) "Error in factorial N=", n
stop 1
else if (n > 1) then
do i = 1, n
ii = to_im(i)
fac = fac * ii
end do
end if
call FM_EXIT_USER_FUNCTION(fac)
end function factorial
end module fac_mod
program main
use FMZM
use fac_mod, only: f=>factorial
implicit none
type(IM) :: res
integer :: n, lenr
character(:), allocatable :: str
character(1024) :: fmat
print *, "enter the value of n"
read *, n
res = f(n)
lenr = 2 + log10(TO_FM(res))
allocate (character(lenr) :: str)
write (fmat, "(A5,I0)") "i", lenr
call im_form(fmat, res, str)
print *, trim(adjustl(str))
end program main

Do-loop ignores if-statement

I'm trying to use an if statement in a do loop which is supposed to generate prime numbers. For that I used modulo to sort out the numbers. After it found a prime number I want it to go a step further and add 1 so that the next prime number can be found and added to the array pzahl. My problem is that the loop seems to ignore that it should go a step further with plauf after it found a prime number so that it just keeps going till infinity... I tried to rearrange the contents of the loop and if statement but it's just not working. Here is the code:
PROGRAM Primzahlen
IMPLICIT NONE
INTEGER :: start, plauf, n, a
INTEGER, ALLOCATABLE, DIMENSION(:) :: pzahlen !array into which the prime numbers should be added
INTEGER :: input
INTEGER, DIMENSION(:), ALLOCATABLE :: alle
PRINT *, "How many prime numbers should be listed"
READ (*,*) input
ALLOCATE (pzahlen(input))
pzahlen(1) = 1
start = 2
plauf = 1
loop1: DO
ALLOCATE(alle(start))
loop2: DO n = 1,start
alle(n)= MODULO(start,n)
END DO loop2
IF (minval(alle) /= 0) THEN ! This is what it seems to ignore.
plauf= plauf + 1
pzahlen(plauf) = start
PRINT *, plauf
END IF
start = start + 1
IF (plauf == eingabe) then
EXIT
END IF
PRINT *, alle
DEALLOCATE(alle)
END DO loop1
PRINT *, "prime numbers:" , pzahlen(1:input)
END PROGRAM Primzahlen
I use the gfortran compiler and write it in Emacs if that helps to know.
It's not ignoring it, it executes correctly:
loop2: DO n = 1,start
alle(n)= MODULO(start,n)
END DO loop2
It doesn't matter what start is, alle(1) will always be zero, as every integer is evenly divisible by 1. That means that minval(alle) will also always be zero, which means that the condition minval(alle) /= 0 is never true, and the statement will never execute.
Added: The last value, alle(start), will also be zero, as every number is evenly divisible by itself.

How to stop a subroutine and raise a flag?

I am writing a program in Fortran 95 (to be compiled with with gfortran) containing a subroutine that performs a certain computation. As suggested in "Fortran 95/2003 for Scientists & Engineers" by S. J. Chapman, I am trying to stop the subroutine when an error is encountered and "throw"[1] an error flag that is "catch"ed[1] by the calling program, that will take all the necessary actions. Ideally, I am going for something like:
! Pseudo-code
PROGRAM my_prog
integer :: error_flag
CALL my_subr (<input_args>, <output_args>, error_flag)
! Also error_flag is an output: 0 -> everything OK, 1 -> error
IF (error_flag /= 0) THEN
WRITE (*,*) 'Error during execution of "my_subr"'
ELSE
... do something ...
END IF
END PROGRAM my_prog
How can I stop the subroutine and gracefully handle the errors?
Here is an example: the subroutine "division" takes an integer input value and iteratively divides it by a value that is the input value decremented by the number of steps-1. When such value reaches zero, a flag should be raised and the subroutine should be exited without performing the division by zero.
SUBROUTINE division (inval, outval, error_flag)
IMPLICIT NONE
INTEGER, INTENT(IN) :: inval
REAL, INTENT(OUT) :: outval
INTEGER, INTENT(OUT) :: error_flag ! 0 -> OK, 1 -> error
INTEGER :: i
REAL :: x
error_flag = 0
x = REAL(inval)
DO i = 0, 10
IF (inval-i == 0) error_flag = 1
! How can I gracefully exit now?
x = x / REAL(inval-i)
END DO
END SUBROUTINE division
PROGRAM my_prog
IMPLICIT NONE
REAL :: outval
INTEGER :: error_flag
CALL division (8, outval, error_flag)
IF (error_flag == 1) THEN
WRITE (*,*) 'Division by zero'
ELSE
WRITE (*,*) 'Output value:', outval
END IF
END PROGRAM my_prog
Notes:
[1] I am borrowing (in a probably inappropriate way) C++'s jargon.
Seeing your example it seems that you are just missing the return statement:
error_flag = 0
x = REAL(inval)
DO i = 0, 10
IF (inval-i == 0) then
error_flag = 1
return
END IF
x = x / REAL(inval-i)
END DO
One possibility would be to change
DO i = 0, 10
IF (inval-i == 0) error_flag = 1
! How can I gracefully exit now?
x = x / REAL(inval-i)
END DO
to
DO i = 0, 10
IF (inval-i == 0) THEN
error_flag = 1
EXIT
END IF
! Now you have gracefully exited
x = x / REAL(inval-i)
END DO
! Code to tidy up if the error flag was set
Here the EXIT statement exits the loop -- Vladimir's answer shows you how to use RETURN to exit the subroutine more immediately. Whichever approach you choose don't forget to assign to outval before leaving the subroutine.