I have a fortran program that never stops executing.
program russianmultiplication
implicit none
integer::x,y,ginx,giny,k=0
print*,'give a number'
read*,x
k=k+x
print*,'one more'
read*,y
if (y==1) then
print*,x
end if
do while(y/=1)
ginx=x*2
giny=y/2
if (mod(giny,2)/=0) then
k=k+ginx
end if
end do
print*,'result',k
end program
Why does this program never end?
You never change y inside the loop, and have no exit statement, either. So either y is 1 on input, in which case the condition for the loop is never true and it never executes, or you never leave the loop since the condition is always true.
Here is perhaps a clearer version of the original program to do Russian peasant multiplication:
PROGRAM Russian_peasant_multiplication
IMPLICIT NONE
INTEGER :: total, x, x_save, y, y_save
total = 0!running total
PRINT *, "x ="
READ *, x
x_save = x
total = total + x
PRINT *, "y ="
READ *, y
y_save = y
PRINT *, y, x
!do while(y/=1)
modulo: DO
IF (y == 1) EXIT!replace DO WHILE for better control
!ginx=x*2
x = x * 2!okay to redefine since saved
!giny=y/2
y = y / 2!okay to redefine since saved
!if (mod(giny,2)/=0) then
IF (MOD(y, 2) /= 0) THEN!keep only odd numbers on the left
PRINT *, y, x
!k=k+ginx
total = total + x
END IF
END DO modulo
PRINT *, " "
PRINT *, x_save
PRINT *, "x"
PRINT *, y_save
PRINT *, "="
PRINT *, total
END PROGRAM Russian_peasant_multiplication
I've added useful comments and also pointed out where the logical was flawed. Hope this helps.
Related
Is there a simple and quick way to multiply a column of a matrix with element of a vector. We can do this explicitly,
program test
integer :: x(3,3), y(3), z(3,3)
x = reshape([(i,i=1,9)],[3,3])
y = [1,2,3]
do i=1,3
z(:,i) = x(:,i) * y(i)
print *, z(:,i)
enddo
end program test
Is there a way to perform the do loop in one line. For example in Numpy python we can do this to do the job in one shot
z = np.einsum('ij,i->ij',x,y)
#or
z = x*y[:,None]
Try
z = x * spread(y,1,3)
and if that doesn't work (no Fortran on this computer so I haven't checked) fiddle around with spread until it does. In practice you'll probably want to replace the 3 by size(x,1) or suchlike.
I expect that this will cause the compiler to create temporary arrays. And I expect it will be easy to find situations where it underperforms the explicit looping scheme in the question. 'neat' one-liners often have a cost in both time and space. And often tried-and-trusted Fortran approach of explicit looping is the one to go with.
Why replace clear easy to read code with garbage?
program test
implicit none
integer i,j
integer :: x(3,3), y(3), z(3,3)
x = reshape([(i,i=1,9)],[3,3])
y = [1,2,3]
z = reshape ([((x(j,i)*y(i) ,j=1,3),i=1,3)], [3,3])
print *, z(1,:)
print *, z(2,:)
print *, z(3,:)
end program test
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.
I'm trying to write some Fortran 90 code to sum up the first 1234 multiples of 3 and 5 (including multiples of both). Here is my code so far:
program sum
implicit none
integer :: x
integer :: y = 5
integer :: z = 3
integer :: n
if (mod(x,y) == 0 .or. mod(x,z) ==0) then
print *, x
n = x
n = x + x
end if
end program sum
However, this code does not print anything to the terminal.
Your code tests the value of x in the if condition:
if (mod(x,y) == 0 .or. mod(x,z) ==0
but the value of x is not set at all. Therefore the result of the program is completely undefined. You need to create some kind of loop. Better two loops.
The most naive approach is to loop from 1 and test all numbers with the above if condition and stop when you have found the desired number of multiples.
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.
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.