If one has a file containing, for example:
1 2 3 4 5
6 7 8 9 10
11 12 13
14 15
16 17
18
19 20
How can one get the correct number of integers (in the given example, 20) from counting them in the file in Fortran?
Here's a little program wot I wrote for this problem. I've subjected it to a tiny battery of tests. It should be fairly clear what the program and subroutine are doing but if you want any explanation of what is going on, ask. If you spot any errors, fix them.
PROGRAM test
USE iso_fortran_env
IMPLICIT NONE
INTEGER :: cnt, filstat
CHARACTER(len=132) :: aline ! change the length if you want to
cnt = 0
OPEN(101,file='data.txt')
DO
READ(101,'(a132)',iostat=filstat) aline
IF (filstat/=0) EXIT
CALL get_int(cnt,aline)
END DO
WRITE(*,*) 'counted ', cnt, 'integers'
CLOSE(101)
CONTAINS
RECURSIVE SUBROUTINE get_int(cnt, str)
INTEGER, INTENT(inout) :: cnt
CHARACTER(*), INTENT(in) :: str
! Local variables
CHARACTER(len= 10), PARAMETER :: digits = '0123456789'
INTEGER :: d1, os, n
! First strip off any leading spaces
d1 = SCAN(str,digits)
IF (d1==0) THEN ! no digit was found
RETURN
END IF
! Read the first integer on the line
READ(str(d1:),*) n
cnt = cnt+1
! Figure out how many character positions to skip over
os = INT(LOG10(REAL(n)))+1
! Recurse
CALL get_int(cnt,str(d1+os+1:))
END SUBROUTINE get_int
END PROGRAM TEST
Interesting question.
Normally you should first tell us what you have tried so far. But anyway.
One solution that I came up with is to create an array that is clearly larger, set all of them to a value that is not valid, then read in from the file.
Make sure that you capture the iostat parameter, otherwise your program will crash.
Then by looking at the first occurrence of that value, you can deduce the size (and you have the values there already):
program read_data
implicit none
integer, dimension(100) :: d
integer :: s, err
d = -9999
open(unit=100, file='data.txt', action='READ', status='OLD')
read(100, *, iostat=err) d
s = 0
do
s = s + 1
if ((s == size(d)) .or. (d(s+1) == -9999)) exit
end do
if (s == size(d)) then
print *, "We might have missed some..."
end if
write(*, '(5I5)') d(1:s)
close(100)
end program read_data
Now this isn't a very good program. You're wasting memory (large array) and to scale up you have to change the code and re-compile.
I'll think about that a bit more later.
I've only been learning Fortran 77 (and its syntax) the last few days, and tried finding answers throughout the site and textbooks already and come up still confused, so I'd appreciate any help. I'm sorry if the formatting on this post is off; this is my first post, and I'm crunched for time.
I'm creating a program to multiply matrices. I want to create a subroutine or a function that will take two matrices as inputs (two 2x2 arrays), and return the multiplied matrix (one 2x2 array). I can't figure out how to get either a subroutine or a function to return an array of fixed size, or how to use the array once it's returned.
I tried using a function, which compiled on its own. But when I tried calling the function from my main program, I couldn't call it on its own:
MATMULT(MAT0, MAT0, MAT0)
1
Error: Unclassifiable statement at (1)
or assign it to another variable (I tried different REALs and arrays):
BLAH = MATMULT(MAT0, MAT0, MAT0)
1
Error: Return type mismatch of function 'matmult' at (1) (INTEGER(4)/REAL(4))
MATRIX1.f:26.22:
BLAH = MATMULT(MAT0, MAT0, MAT0)
1
Warning: Type mismatch in argument 'x' at (1); passed INTEGER(4) to REAL(4)
BLAH = MATMULT(MAT0, MAT0, MAT0)
1
Warning: Rank mismatch in argument 'x' at (1) (scalar and rank-2)
Since arrays are passed by reference, I'm really not sure what the function is returning, so how can I use the output matrix, if that is indeed the function's output?
I also tried using a subroutine, but (in addition to still not knowing what it's returning or where) then I get a "Two main PROGRAMs" error - so the compiler isn't differentiating between the main program and the subroutine. This might be a problem with my syntax on subroutines? I tried a few different things, but here's my most recent iteration of the code (I'm just trying to get the array-passing to work, so there's not actual matrix multiplication in here yet):
PROGRAM MATRIX1
INTEGER N
REAL A, B, MAT0(2,2), MATF(2,2), X(2,2), Y(2,2), Z(2,2)
REAL BLAH
PRINT *, " ENTER THE VALUE OF A: "
READ *, A
PRINT *, " ENTER THE VALUE OF B: "
READ *, B
PRINT *, " ENTER THE NUMBER OF MULTIPLICATIONS: "
READ *, N
C Creates the initial matrix
MAT0(1,1) = 1.0 - A
MAT0(1,2) = A
MAT0(2,1) = B
MAT0(2,2) = 1.0 - B
PRINT *, "M = ", MAT0
CALL MATMULT(MAT0, MAT0, MAT0)
PRINT *, "FINAL "
STOP
END PROGRAM
REAL SUBBROUTINE MATMULT(X, Y, Z)
END SUBROUTINE
Or (edited to add some of the recommended changes) with a function:
PROGRAM MATRIX1
INTEGER N
REAL A, B, MAT0(2,2), MATF(2,2), X(2,2), Y(2,2), Z(2,2)
REAL MATMULT(2,2)
PRINT *, " ENTER THE VALUE OF A: "
READ *, A
PRINT *, " ENTER THE VALUE OF B: "
READ *, B
PRINT *, " ENTER THE NUMBER OF MULTIPLICATIONS: "
READ *, N
C Creates the initial matrix
MAT0(1,1) = 1.0 - A
MAT0(1,2) = A
MAT0(2,1) = B
MAT0(2,2) = 1.0 - B
PRINT *, "M = ", MAT0
Z = MATMULT(X, Y)
STOP
END PROGRAM
FUNCTION MATMULT(X, Y)
REAL X(2,2), Y(2,2), Z(2,2), MATMULT(2,2)
RETURN
END
I'm still getting errors:
Z = MATMULT(X, Y)
1
Warning: Legacy Extension: REAL array index at (1)
MATRIX1.f:28.19:
Z = MATMULT(X, Y)
1
Error: Array index at (1) is an array of rank 2
In this era there is no reason for use FORTRAN 77. Fortran 90/95/2003 is easier to use, more powerful, and better assists the programer in finding mistakes. gfortran is an excellent open-source compiler.
Here is an example in Fortran 95 of a similar program/function: a function that implements a vector-cross product. The example shows the function and program in the same file (there are other approaches) with the function receiving two vectors and returning one vector. Example: Computing the cross product of two vectors in Fortran 90
You mention several problems in your question. Certainly your work will be enhanced using more recent Fortran dialects, as given in the answers by M. S. B. and Ilmirus. And you really should be using implicit none (even for Fortran 77 a lot of compilers support that - and lower case - as an extension).
Coming to the conceptual part, I must say that you need to continue your learning. However, if you want a function which returns the matrix product then you will have something like
function matmult(x, y)
real x(2,2), z(2,2), matmult(2,2)
... calculation of matmult
end function matmult
Followed by
z = matmult(x,y)
in the main program, where z is real z(2,2), rather than the scalar blah you have in your example, and is your result.
Coming to your subroutine, there are indeed problems: real subroutine matmult(x,y,z) requires not the real. Then calling this with call matmult(mat0, mat0, mat0) where you intend to update mat0 with a result is asking for aliasing problems. call matmult(x,y,z) will "store the result" where the subroutine calculations put it. Using intent as given by Ilmirus is a good guide to the behaviour desired by the programmer.
Finally, if you just want to get the result of multiplying A and B as matrices and storing in C: use C = matmul(A,B) with a later-than-F77 compiler.
However, in Fortran 77 one doesn't return array results, so the subroutine approach is the one to go for. In response to your edit:
REAL MATMULT(2,2)
is declaring matmult an array, not a function, so references to matmult(X,Y) give rise to your error.
There are two ways to do this:
1) Subroutine. Declare a subroutine like you did. However, specify input and output parameters:
REAL, INTENT(IN) :: X(2,2), Y(2,2)
REAL, INTENT(OUT) :: Z(2,2)
and call the subroutine using call keyword: CALL MATMULT
2) Function. Also specify input parameter, but now return value of the function:
! Insert calculation
MALMULT = ...
Don't forget to declare it in proper way: FUNCTION MATMULT(x,Y)
Call it: Z = MATMULT(X,Y)
Basically I am looking to enter X,Y pairs read from a file into arrays of length n where n is the number of lines(and thus x,y pairs) in the file. Unfortunately all my attempts at determining the length of the file then using that to set the size of the array have been unsuccessful. How can I accomplish this in Fortran 77? Hoping I am not missing something obvious, I am more used to Python and Java where this is rather trivial.
PS. Before asking this I looked around and it seemed that the general feeling was that you just set the size larger then you would expect it to be but that seems very memory wasteful and inefficient.
The solution is to use Fortran 90/95/2003/2008, which has the capabilities needed for your problem, while FORTRAN 77 doesn't. Read the file once to determine the number of data items. Rewind the file. Allocate the array of the required length. Read the file again, reading into the arrays.
Using Fortran 2003/2008 (not tested):
use iso_fortran_env
real :: xtmp, ytmp
real, dimension (:), allocatable :: x, y
integer :: i, n
integer :: Read_Code
open (unit=75, file=...)
n = 0
LengthLoop: do
read ( 75, *, iostat=Read_Code) xtmp, ytmp
if ( Read_Code /= 0 ) then
if ( Read_Code == iostat_end ) then
exit LengthLoop
else
write ( *, '( / "read error: ", I0 )' ) Read_Code
stop
end if
end if
n = n + 1
end do LengthLoop
allocate (x(n))
allocate (y(n))
rewind (75)
do i=1, n
read (75, *) x(i), y(i)
end do
close (75)
I try to implement a code that read in a number n, creates a vector to store n double precision numbers, read this number, call a subroutine printminmax() to find min and max. My code work perfect for normal numbers (integer,real etc) but when i have scientific notation (0.3412E+01) stack.Why? I thought with * read all the formats. Thanks
implicit none
integer, dimension(:), allocatable :: x
integer :: n
open (unit=77, file='input2.dat', action='read', status='old')
read(77,*), n
allocate(x(n))
call printminmax(n)
deallocate(x)
end
subroutine printminmax(y)
implicit none
integer, dimension(:), allocatable :: x
integer :: y,max,min,i
allocate(x(y))
read(77,*) x
!print *,'Maximun=', maxval(x)
!print *,'Minimun=', minval(x
!initialize the value max & min
max=x(1)
min=x(1)
do i=2,y
if (x(i)>max) max=x(i)
if (x(i)<min) min=x(i)
end do
write(*,*) 'Maximum=',max
write(*,*) 'Minimum=',min
end subroutine printminmax
one example of the stack input is
1000
5.39524398466520e-01
9.85099770130787e-01
7.38946122872518e-01
6.47771620257608e-01
8.80871051119695e-01
2.99375585725816e-02
the error that i take for scientific notation is
At line 13 of file io.f90 (unit = 77, file = 'input3.dat')
Fortran runtime error: Bad integer for item 1 in list input
ok i found it.I should have double precision on x, no integer.
i wish to use dynamic declaration for a large array in fortran95 with allocate(matrix(size)),while size=10^7 and the content real*8 numbers.If size<13*10^6 everything runs smoothly without any error, but if size>13*10^6 then i get a segmentation fault on the run. It is important that I use dynamic declaration since the size of the array is calculated within the program. I use Mac OSX 64bit and gfortran 4.6.Can someone help me?
10**7 elements of real*8 is 76 MiB, so should pose no problem (I have successfully allocated several GiB arrays with GFortran, though I don't use OSX). Can you post a self-contained example in order to further analyze your problem?
Here is an example using an array of size 10**8. It worked for me with Mac OS X and gfortran 4.6. Does it work on your computer?
program test_lrg
integer, parameter :: DoubleReal_K = selected_real_kind (14)
integer, parameter :: QuadReal_K = selected_real_kind (32)
integer, parameter :: RegularInt_K = selected_int_kind (8)
integer, parameter :: VeryLongInt_K = selected_int_kind (18)
real (DoubleReal_K), dimension (:), allocatable :: array
integer (RegularInt_K) :: i
integer (RegularInt_K), parameter :: N = 100000000_RegularInt_K
real (QuadReal_K) :: sum
integer (VeryLongInt_K) :: CalcSum
allocate (array (N))
do i=1, N
array (i) = i
end do
do i=1, N
sum = sum + array (i)
end do
write (*, *) sum
CalcSum = N
CalcSum = ( CalcSum * (CalcSum + 1_VeryLongInt_K) ) / 2_VeryLongInt_K
write (*, *) CalcSum
stop
end program test_lrg
Try compiling with debugging options, such as:
-fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -fwhole-file -fcheck=bounds -fcheck=do -fcheck=mem -fcheck=recursion -std=f2008 -pedantic -fbacktrace