How do `DO` loops work in Fortran 66? - fortran

I'm reading an old book I found in a second-hand book shop (again). This one is called "Fortran techniques - with special reference to non-numerical applications", by A. Colin Day, published by Cambridge University Press in 1972. It is, after all, very important to keep up with the latest in software development ;-)
This book claims to cover Fortran-66 (X3.9-1966), aka Fortran-IV, with a minor departure from that standard for DATA statements which isn't relevant here.
The trouble is, the book seems to leave a lot to guesswork, and my guesses are pretty uncertain WRT the DO loop. This is in chapter 1, so not a very good sign.
Here is one example...
DO 15 I = 1, 87
J = I - 44
In the DO line, 1 and 87 seem to represent the inclusive range for the loop - I takes values 1 to 87 inclusive, so J takes values -43 to +43 inclusive. However, what does the 15 represent?
Another example is...
N = 1
DO 33 I = 1, 10
...
33 N = N + N
In this case, 33 looks like a label or line number - presumably the last line executed before the loop repeats (or exits). But 33 is an odd number to choose just as an arbitrary label.
EDIT That was a mistake - see the answer by duffymo - How do `DO` loops work in Fortran 66?
And the very next example after that is...
DO 33 I = 1, 10
N = 2 ** (I-1)
Again using the same 33, but without any line being explicitly labelled with it.
Am I being confused because these are short snippets taken out of context? What does the n in DO n ... represent?

Here is a complete program that should answer some of your questions. One can easily test this history question ... FORTRAN IV is still supported by numerous compilers, though portions of FORTRAN IV are either officially obsolescent or, in my opinion, should be obsolete. I compiled and checked this program with both g77 (which is close to obsolete since it is long unsupported) and gfortran.
Here is a sample program:
implicit none
integer i
real q
q = 1.0
do i=1, 10
q = q * 1.5
end do
write (6, *) "modern loop: q =", q
q = 1.0
do 100 i=1, 10
q = q * 1.5
100 continue
write (6, *) "loop with continue: q =", q
q = 1.0
do 200 i=1, 10
200 q = q * 1.5
write (6, *) "loop without continue: q =", q
stop
end
And how to compile it with gfortran:
gfortran -ffixed-form -ffixed-line-length-none -std=gnu test_loops.for -o test_loops.exe
Re your question: if you terminate the loop with a labeled line that is an executable code, is that line part of the loop? The output of the program clearly shows that the labeled line IS part of the loop. Here is the output of gfortran:
modern loop: q = 57.665039
loop with continue: q = 57.665039
loop without continue: q = 57.665039

The line number tells the code where to go when the loop is complete.
Yes, the numbers are odd, arbitrary, and meaningless. It's part of what made FORTRAN hard to read and understand.

The number 15 known as a "Label" it was decided by the programmer. Depending on organisational standards these numbers were controlled and followed specific rules. Although some programmers didn't keep to standards and their code was a mess; Comments and line indentations were also part of standards followed by most.

Related

Cyclic Redundancy check : Single and double bit error

Found this in the book by Forouzan (Data Communications and Networking 5E). But, not able to understand the logic behind this.
This is in the context of topic two isolated single-bit errors
In other words, g(x) must not divide x^t + 1, where t is between 0 and n − 1. However, t = 0 is meaningless and t = 1 is needed as we will see later. This means t should be between 2 and n – 1
why t=1 is excluded here? (x^1 + 1) is two consecutive errors, it must also be detected right using our g(x).
The third image states that (x+1) should be a factor of g(x), but this reduces the maximum length that the CRC is guaranteed to detect 2 bit errors from n-1 to (n/2)-1, but it provides the advantage of being able to detect any odd number of bit errors such as (x^k + x^j + x^i) where k+j+i <= (n/2)-1.
Not mentioned in the book, is that some generators can detect more than 3 errors, but sacrifice the maximum length of a message in order to do this.
If a CRC can detect e errors, then it can also correct floor(e/2) errors, but I'm not aware of an efficient algorithm to do this, other than a huge table lookup (if there is enough space). For example there is a 32 bit CRC (in hex: 1f1922815 = 787·557·465·3·3) that can detect 7 bit errors or correct 3 bit errors for a message size up to 1024 bits, but fast correction requires a 1.4 giga-byte lookup table.
As for the "t = 1 is needed", the book later clarifies this by noting that g(x) = (x+1) cannot detect adjacent bit errors. In the other statement, the book does not special case t = 0 or t = 1, it states, "If a generator cannot divide (x^t + 1), t between 0 and n-1, then all isolated double bit errors can be detected", except that if t = 0, (x^0 + 1) = (1 + 1) = 0, which would be a zero bit error case.

Why can't my program print my statements?

There is 3 columns in the file i'm reading and I want to average each column and take the std. The code compiles now, but nothing is being printed.
Here is my code:
program cardata
implicit none
real, dimension(291) :: x
intEGER I,N
double precision date, odometer, fuel
real :: std=0
real :: xbar=0
open(unit=10, file="car.dat", FOrm="FORMATTED", STATUS="OLD", ACTION="READ")
read(10,*) N
do I=1,N
read(10,*) x(I)
xbar= xbar +x(I)
enddo
xbar = xbar/N
DO I =1,N
std =std +((x(I) -xbar))**2
enddo
std = SQRT((std / (N - 1)))
print*,'mean:',xbar
print*, 'std deviation:',std
close(unit=10)
end program cardata
I am fairly new to this, any input will be greatly appreciated.
Example of car.dat:
date odometer fuel
19930114 298 22.4
19930118 566 18.1
19930118 800 18.9
19930121 960 15.8
19930125 1247 19.8
19930128 1521 17.1
19930128 1817 19.8
19930202 2079 18.0
19930202 2342 10.0
19930209 2511 16.4
19930212 2780 16.7
19930214 3024 19.0
19930215 3320 17.7
19930302 3560 16.4
19930312 3853 18.8
19930313 4105 18.5
From the car.dat that you gave in the comments, it's surprising that the program doesn't show anything. When I run it, it shows a very clear runtime error:
$ gfortran -o cardata cardata.f90
$ ./cardata
At line 12 of file cardata.f90 (unit = 10, file = 'car.dat')
Fortran runtime error: Bad integer for item 1 in list input
You seem to be copying code from another example without really understanding what it does. The code, as you wrote it, expects the file car.dat to be in a certain format: First an integer, which corresponds to the number of items in the file, then a single real per line. So something like this:
5
1.2
4.1
2.2
0.4
-5.2
But with your example, the first line contains text (that is, the description of the different columns), and when it tries to parse that into an integer (N) it must fail.
I will not give you the complete example, as I have the nagging suspicion that this is some sort of homework from which you are supposed to learn something. But here are a few hints:
You can easily read several values per line:
read(10, *) date(I), odometer(I), fuel(I)
I'm assuming here that, different to your program, date, odometer, and fuel are arrays. date and odometer can be integer, but fuel must be real (or double precision, but that's not necessary for these values).
You need to jump over the first line before you can start. You can just read the line into a dummy character(len=64) variable. (I picked len=64, but you can pick any other length that you feel confident with, but it should be long enough to actually contain the whole line.)
The trickiest bit is how to get your N as it is not given at the beginning of the file. What you can do is this:
N = 0
readloop : do
read(10, fmt=*, iostat=ios) date(N+1), odometer(N+1), fuel(N+1)
if (ios /= 0) exit readloop
N = N + 1
end do readloop
Of course you need to declare INTEGER :: ios at the beginning of your program. This will try to read the values into the next position on the arrays, and if it fails (usually because it has reached the end of the file) it will just end.
Note that this again expects date, odometer, and fuel to be arrays, and moreover, to be arrays large enough to contain all values. If you can't guarantee that, I recommend reading up on allocatable arrays and how to dynamically increase their size.

Strange behavior while calling properties from REFPROP FORTRAN files

I am trying to use REFPROPs HSFLSH subroutine to compute properties for steam.
When the same state property is calculated over multiple iterations
(fixed enthalpy and entropy (Enthalpy = 50000 J/mol & Entropy = 125 J/mol),
the time taken to compute using HSFLSH after every 4th/5th iteration increases to about 0.15 ms against negligible amount of time for other iterations. This is turning problematic because my program places call to this subroutine over several thousand times. Thus leading to abnormally huge program run times.
The program used to generate the above log is here:
C refprop check
program time_check
parameter(ncmax=20)
dimension x(ncmax)
real hkj,skj
character hrf*3, herr*255
character*255 hf(ncmax),hfmix
C
C SETUP FOR WATER
C
nc=1 !Number of components
hf(1)='water.fld' !Fluid name
hfmix='hmx.bnc' !Mixture file name
hrf='DEF' !Reference state (DEF means default)
call setup(nc,hf,hfmix,hrf,ierr,herr)
if (ierr.ne.0) write (*,*) herr
call INFO(1,wm,ttp,tnbp,tc,pc,dc,zc,acf,dip,rgas)
write(*,*) 'Mol weight ', wm
h = 50000.0
s = 125.0
c
C
DO I=1,NCMAX
x(I) = 0
END DO
C ******************************************************
C THIS IS THE ACTUAL CALL PLACE
C ******************************************************
do I=1,100
call cpu_time(tstrt)
CALL HSFLSH(h,s,x,T_TEMP,P_TEMP,RHO_TEMP,dl,dv,xliq,xvap,
& WET_TEMP,e,
& cv,cp,VS_TEMP,ierr,herr)
call cpu_time(tstop)
write(*,*),I,' time taken to run hsflsh routine= ',tstop - tstrt
end do
stop
end
(of course you will need the FORTRAN FILES, which unfortunately I cannot share since REFPROP isn't open source)
Can someone help me figure out why is this happening.?
P.S : The above code was compiled using gfortran -fdefault-real-8
UPDATE
I tried using system_clock to time my computations as suggested by #Ross below. The results are uniform across the loop (image below). I will have to find alternate ways to improve computation speed I guess (Sigh!)
I don't have a concrete answer, but this sort of behaviour looks like what I would expect if all calls really took around 3 ms, but your call to CPU_TIME doesn't register anything below around 15 ms. Do you see any output with time taken less than, say 10 ms? Of particular interest to me is the approximately even spacing between calls that return nonzero time - it's about even at 5.
CPU timing can be a tricky business. I recommended in a comment that you try system_clock, which can be higher precision than CPU_TIME. You said it doesn't work, but I'm unconvinced. Did you pass a long integer to system_clock? What was the count_rate for your system? Were all the times still either 15 or 0 ms?

Open file and close file statement positioning: best practice, advantages, disadvantages

I have a code, containing many loop iterations, with open file and close file statements positioned as follows:
Main loop
do work
open files
write to files
close files
continue work
end loop
But, an alternative is:
open files
Main loop
do work
write to files, [flush]
continue work
end loop
close files
Is there a "best practice" to positioning open file and close file statements containing many loop iterations? Are there advantages / disadvantages to each? Will I see performance differences? Memory restrictions? Future development issues down the line?
I'm mainly coding in Fortran (hence the tag), however, I would like to know if this is language dependent or not, since I also program in other languages. Any help is greatly appreciated.
If you can do a task outside the loop, you better do it, since every time you add it to the loop queue results in worse performance (n times instead of 1). Therefore, declaring variables or opening files before the loop is better than repeating it with every iteration.
Main loop
do work - cost: k * n
open files - cost: q * n
write to files - cost: r * n
close files - cost: s * n
continue work - cost: l * n
end loop
Total: n * (k + q + r + s + l)
open files - cost: q
Main loop
do work - cost: k * n
write to files - cost: r * n
continue work - cost: l * n
end loop
close files - cost: s
Total: n * (k + r + l) + q + s
s and q are very expensive, since accessing files on the system disk costs much more time and is very slow compared to accessing variables or performing calculation, since it is needs to get the data from the disk, as opposed to the variables that are stored in the RAM and are easily accessible through the code flow. See more on caching and io buffering for that.
As for performance:
$ python -m timeit 'open("hw.txt").read()'
1000 loops, best of 3: 240 usec per loop
$ python -m timeit 'a=2;b=3;c=a**b'
100000 loops, best of 3: 2.15 usec per loop
As usual, you should profile your specific code to see what are the bottlenecks. However, in general, opening and closing files is very expensive.
Consider the following:
def foo():
f = open('bar.txt', 'w')
for i in range(1000):
f.write('a')
f.close()
def bar():
for i in range(1000):
f = open('bar.txt', 'w')
f.write('a')
f.close()
Let's time it:
>>> %timeit foo()
10000 loops, best of 3: 190 µs per loop
>>> %timeit bar()
10 loops, best of 3: 47.8 ms per loop
So, opening and closing is extremely expensive.
What are the advantages (or at least mitigating factors) for the constant opens and closes?
Less open file descriptors.
When you close a file, the data is flushed to it. Of course you could just call flush, but that is an expensive operation in itself, and the time differences would become narrower.
If you don't have critical data (i.e., you can just rerun the program if it crashes), and don't have too many open file descriptor problems - few opens and closes will probably be faster.
Doing a task many times (in the loop) versus doing it just once (outside the loop) is obviously going to be more costly - regardless of the language used.

C++: How to get vector to print user input?

I'm having some trouble figuring out how to print out my vector's user input. I think there's something wrong specifically with my iterator loop, but I'm not sure what. I've been toying around with this and I'm stumped. I'm also having trouble with my sentinel value - my program ceases to continue after entering in my sentinel value. Am I missing something?
Any help you could provide would be greatly appreciated.
Here's my code: (there are some variables here that you might notice that aren't being used in this sample of code. i'm using those variables for another portion of my program).
Any help that you could provide in regards to this would be INCREDIBLY helpful. Thank you.
You're declaring your check_amounts vector a second time, right before your output loop, so you're outputting the contents of an empty vector. Delete the second declaration.
Your code got caught in infinite loop at :
for (i = 0; amount < length; i++) length /= 10;
Because amount = -1, length = 0.
Also do not use != for double values, e.g. (amount != -1). Use < or > . Equality check is not reliable due to inexact bit-pattern
this is what i get when i run your code:
This program inputs a dollar amount and prints it in check-format.
Input up to five check amounts, one at a time. (Enter -1 to quit)
5
Input up to five check amounts, one at a time. (Enter -1 to quit)
10
Input up to five check amounts, one at a time. (Enter -1 to quit)
15
Input up to five check amounts, one at a time. (Enter -1 to quit)
20
Input up to five check amounts, one at a time. (Enter -1 to quit)
25
The check-formated dollar amount for your check(s) are printed as follows: 5 **** 25.00
10 **** 25.00
15 **** 25.00
20 **** 25.00
25 **** 25.00
Can't see a problem with printing out vector's user input. Avik Paul is right for the sentinel case by the way. You should be using the last valid amount maybe.