What does call sleep(1) mean in Fortran? - fortran

program democonstanta
implicit none
c constanta
integer, parameter :: MIN_VALUE = 0
integer, parameter :: MAX_VALUE = 100
c var declaration
integer :: i = MIN_VALUE
do while (i <=MAX_VALUE)
write(*,'(a14)') "Please wait... "
write(*,'(i3,a2)', advance='no') i, "%"
call sleep(1)
if (i .it. MAX_VALUE) then
call execute_command_line("clear")
end if
i = i + 1
end do
call execute_command_line("clear")
write(*,'(a3)') "End."
end program democonstanta

Reference: https://gcc.gnu.org/onlinedocs/gfortran/SLEEP.html
It simply sleeps (waits) for a given number of seconds. In your case - one.

Related

How to use the value of an allocatable argument?

I have the following code and I would like to save the value of idx to use afterwards.
program use_value_allocatable
implicit none
integer :: i, ii
integer, dimension(3) :: array_save
character(1), dimension(3) :: array_char_ref = (/'a','b','c'/), array_char_1 = (/'c','a','b'/)
integer, allocatable :: idx(:)
array_save = 0
do i = 1, 3
idx = pack([(ii,ii=1,3)], array_char_ref == array_char_1(i) )
print*, 'i=', i, ', idx=', idx, ', array_save(i) =', array_save(i)
!!$ array_save(i) = idx
deallocate(idx)
end do
end program use_value_allocatable
Having array_save(i) = idx in the code leads to an error as follows:
Error: Incompatible ranks 0 and 1 in assignment at (1)
So, I can conclude that I cannot use the value of an allocatable variable (here idx). How I can circumvent this problem?
P.S.: in this example I assume that idx will always be an integer of dimension 1
As you say, "idx will always be an integer of dimension 1", so you just need
array_save(i) = idx(1)
i.e. you need to store the first (and only) element of idx in array_save(i), rather than the whole array.
A side note: you do not need the line deallocate(idx). idx will be implicitly re-allocated by the line idx = ..., and will be automatically deallocated when it drops out of scope.

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.

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

FORTRAN logic notproblem

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.

Pass arguments and take sum

I am passing two values to my Fortran program, I need to get the sum of those arguments and print it as result:
I have the program for reading arguments as follows:
PROGRAM Argtest
IMPLICIT NONE
integer*4 nargs,i
character arg*80
nargs = iargc()
do i = 0,nargs
call getarg(i, arg)
print '(a)', arg
end do
END
I am passing the values 10 and 20.
I tried like this:
PROGRAM Argtest
IMPLICIT NONE
integer:: nargs,i
character:: arg
integer:: num1
integer:: num2
integer:: result
nargs = iargc()
do i = 1,nargs
call getarg(i, arg)
!print *, arg
IF( i == 1) THEN
num1 = ichar(arg)
ELSE IF(i == 2) THEN
num2 = ichar(arg)
ELSE
end IF
end do
result = num1+num2
print *, num1
print*,num2
END
I need to print the answer as 30. But I am getting values 49 and 50 instead of getting 10 and 30. Please help me.
Here is a very simple version: It reads the arguments as strings, converts them into ints one after the other, and adds them all up.
PROGRAM Argtest
IMPLICIT NONE
integer*4 nargs,i
character arg*80
integer :: total, int_arg
nargs = iargc()
total = 0
do i = 1,nargs
call getarg(i, arg)
read(arg, *) int_arg
total = total + int_arg
end do
print *, "total is ", total
END
Note that I am starting from argument 1, not 0 (as that is your program name, and can't be converted into a number).
You have now updated your question: ichar converts a single character into the integer that corresponds to that character's ASCII code.
You need to use read(ch_num, '(I)') int_num to convert a string like "10" to the integer number 10.