2

I'm totally new to Fortran, and I'm trying to learn the language here: http://www.fortrantutorial.com/files-precision/index.php. I have some basic experience with C and Python, but not much, like introduction class and such.

So in exercises 4.1, they ask me to input some numbers from a file, and check if these numbers are even or odd. Here is the code to input the numbers:

    program readdata
    implicit none
    !reads data from a file called mydata.txt
    real :: x,y,z
    open(10,file='mydata.txt')
            read(10,*) x,y,z
    print *,x,y,z
    end program  readdata

The file mydata.txt contains some random numbers. And they can check if the number is even or odd by:

   if (mod(num,2)>0) then……

My question is that: if this file have like 10, or 1000 numbers, do I have to manually assign every single one of them? Is there any other way for me to do quick calculation with mass numbers situation like that?

Kim Dong
  • 155
  • 8
  • after opening the file, loop over how many lines you want to read. Either you overwrite the variables every read and do the calculations directly in the loop, or store the numbers in arrays and loop over the arrays later. Depends on whether you need the variables later on. – Fl.pf. Oct 11 '16 at 12:27
  • We don't normally post the final code here in the questions. The question normally contains just your question. – Vladimir F Героям слава Oct 11 '16 at 17:23
  • Oh ok guess I'll delete it – Kim Dong Oct 11 '16 at 18:05

2 Answers2

4

Every read also moves the read pointer forwards. So with every new read, a new line is read in from the file.

The easiest thing to do is to keep reading until the READ statement returns an error. Of course, you have to pass a variable for the READ to write its error into. Something like this:

program readdata
    implicit none
    real :: x, y, z
    integer :: iounit, ios
    open(newunit=iounit, file='mydata.txt', iostat=ios, action='READ')
    if (ios /= 0) STOP 1
    do
        read(iounit, *, iostat=ios) x, y, z
        if (ios /= 0) exit
        print *, x, y, z
    end do
    close(iounit)
end program readdata

Update: If you're limited to Fortran 95, as OP suggested in his comments, here's what to change: Instead of

integer :: iounit, ios
open(newunit=iounit, ...)

you use

integer :: ios
integer, paramter :: iounit = 100
open(unit=iounit, ...)

All that's important is that iounit is a number, greater than 10, which is not used as a unit for any other read/write operation.

chw21
  • 7,970
  • 1
  • 16
  • 31
  • This is Fortran 08 right? I can't use the newunit feature, since I'm using FTN95. Is there any other way? – Kim Dong Oct 11 '16 at 14:01
  • 1
    You're right - `newunit` is a recent addition. If that's not available, you can set `iounit` to a number you're sure is safe - something like 100 is almost always ok. Then open the file using `unit=`, rather than `newunit=`. – Ross Oct 11 '16 at 14:59
  • If you want to save the data then you could read it twice. First time with a counter just into some junk variable. Then allocate your storage variable based on that. Second read, rewind iounit, then fill your storage variable from 1 to counter. – Mark S Oct 12 '16 at 06:22
  • @mark-s there is almost always a better method than to read the same data twice from file. Some ideas on how to grow an array are here: http://stackoverflow.com/questions/8264336/how-to-get-priorly-unkown-array-as-the-output-of-a-function-in-fortran – chw21 Oct 12 '16 at 22:56
  • @chw21 I'm not understanding how your example is the same. I know 4 options to read a file of unknown size (1) have data size in the header (2) read into a small static array and fill a dynamic array from that in chunks (3) read the file twice (4) Create a huge static array that you hope not to fill completely. What other ones did I miss? – Mark S Oct 15 '16 at 04:28
  • 1
    Okay, this isn't really related to the question, but here's the short comment answer: File I/O is slow, compared to, for example, memory. So it's usually not a good idea to read data twice. But that means that you don't know how large your arrays need to be before you start reading, which in turn means that you might have to dynamically grow the array. The second example in the accepted answer on that question shows a good way, using `move_alloc`, to grow an array if you find out you need a bigger one while already partly populated. – chw21 Oct 16 '16 at 08:53
-3

well a mass of numbers means that X, Y, and Z need to be more than a single number of each... so something like this should get you vectored towards a solution:

    program readdata
    implicit none
    !reads data from a file called mydata.txt
    INTEGER, PARAMETER              :: max2process = 10000
    INTEGER                         :: I
    INTEGER                         :: K = 0
    real   , DIMENSION(max2process) :: x,y,z
    LOGICAL, DIMENSION(max2process) :: ODD = .FALSE.
    open(10,file='mydata.txt')
    10  CONTINUE
    X(:) = 0
    Y(:) = 0
    K(:) = 0
    DO I = 1, max2process
      K = K + I
      read(10,*, EOF=99) x(I), y(I), z(I)
      print *,x(I), y(I), z(I)
    ENDDO
    WRITE(*,22) I, MINVAL(X(1:I)), MAXVAL(X(1:I)
22  FORMAT(' MIN(X(1:',I5,')=',0PE12.5,'  Max=',0PE12.5)
    odd = .FALSE.
    WHERE (MODULO(X, 2) /= 0)
      ODD = .TRUE.
    ENDWHERE
    DO I = 1, 10
      WRITE(*,88) I, X(I), odd(I)
88    FORMAT('x(', I2,')=',0PE12.5,' odd="',L1,'"')
    EBDDO
    WRITE(*,*) ' we did not hit the end of file... Go back and read some more'
    GOTO 10

99  WRITE(*,*) 'END of file reached at ', (K-1)
    end program  readdata

Basically something like that, but I probably have a typo (LTR). If MODULO is ELEMENTAL then you can do it easily... And MODULO is ELEMENTAL, so you are in luck (which is common).

There is a https://rosettacode.org/wiki.Even_or_Odd#Fortran that looks nice. the functions could be further enhanced using ELEMENTAL FUNCTION. that should give you enough to work it out.

or you could read the file to find the size, close and reopen it, and then allocate X, Y, Z and Odd... the example i gave was more of a streaming example. one should generally use a DO WHILE rather than a GOTO, but starting out a GOTO can be conceptually easier. (You need an EXIT or some DO WHILE (IOSTAT /= ) in order to break out)

Holmz
  • 714
  • 7
  • 14
  • 2
    what is this, fixed form f77/f90 hybrid :/ – Fl.pf. Oct 11 '16 at 13:09
  • 3
    Arrgghhhh, it burns my eyes, ... Note, *inter alia*, that `x(:)` on the lhs of an assignment is subtly different from `x` when `x` is an array. If one is not entirely comfortable with the subtle differences better to use `x` to mean the whole array. – High Performance Mark Oct 11 '16 at 13:24
  • 1
    This is *not* modern fortran and I do not recommend this use of GOTO's. It makes code difficult to read and was rendered unnecessary more than 20 years ago. Downvote from me. – Ross Oct 11 '16 at 14:57
  • 1
    As High Performance Marks notes, it hurts https://software.intel.com/en-us/blogs/2008/03/31/doctor-it-hurts-when-i-do-this – Vladimir F Героям слава Oct 11 '16 at 15:04
  • This looks quite difficult for a beginner like me, but I'll try to understand this some day. Thanks for the help though! :D – Kim Dong Oct 11 '16 at 17:02
  • Specific lessons NOT to learn from this answer: use of `modulo` for determining oddness of real numbers, `GOTO`, `EBDDO` (OP certainly didn't compile this !), incrementing `K` on every iteration of the first `do` loop but never using the value of `K`, mis-counting left and right parentheses (OP certainly didn't compile this), probably other elements too. – High Performance Mark Oct 12 '16 at 14:49