Fortran DO loop, warning to use integer only
Asked Answered
V

1

7

I installed gfortran on my Ubuntu 15.04 system. While compiling Fortran code, the DO loop asks to take integer parameters only and not real values or variables. That includes the loop variable and the step expression. Why can't it take real values too?

The following is a program taken from here, exercise 3.5 of the section nested do loops.

        program  xytab
        implicit none
        !constructs a table of z=x/y for values of x from 1 to 2 and 
        !y from 1 to 4 in  steps of .5
        real         ::   x, y, z 
        print *, '           x           y           z'
        do  x = 1,2
            do y = 1,4,0.5
                z = x/y
                print *, x,y,z
            end do
        end  do
        end  program xytab

The error shown after compiling is:

xytab.f95:8.4:

 do y = 1,4,0.5
    1
Warning: Deleted feature: Loop variable at (1) must be integer
xytab.f95:8.12:

 do y = 1,4,0.5
            1
Warning: Deleted feature: Step expression in DO loop at (1) must be integer
xytab.f95:7.3:

do x = 1,2
   1
Warning: Deleted feature: Loop variable at (1) must be integer
Vitrescent answered 8/6, 2015 at 11:13 Comment(5)
I've answered that a Fortran-compliant program must use integer variables/expressions, but note that your compiler is quite happy to go along with using reals. These are just warnings. Ones I'd strongly suggest you heed, but it's still a non-portable option for you.Excisable
Oh right! That's a warning. Nicely pointed out. Great. And thanks. but why do you say that it's non-portable?Vitrescent
It's non-portable because a Fortran 95+ compiler needn't accept the program as it doesn't follow the rules specified by the standard. It's possible that many current compilers with a Fortran 77/90 heritage have code to accept it, but it's not something I would make an effort to put into a brand new compiler.Excisable
not that I recommended it but you could convert to a do while loop (say you wanted to try to mimic the behavior of some old code )Romelda
funny that tutorial claims the code to be F95+ .. Someone ought to let them know. (They expect you to "register" just to sent them a note though)Romelda
E
16

The Fortran standard now requires that a do construct's loop control is given by (scalar) integer expressions and that the loop variable is a (scalar) integer variable. The loop control consists of the start, step, and stop expressions (your step expression is 0.5). See R818 and R819 (8.1.6.2) of the Fortran 2008 document. That, then, is the short and simple answer: the standard says so.

It's a little more complicated than that, as the messages from the compiler suggest. Using other forms for loop control was present in Fortran up until Fortran 95. That is, from Fortran 95 onward using real expressions is a deleted feature.

What harm is there in using real expressions? Used correctly, one could imagine, there is no harm. But there's real difficulty in portability with them.

Consider

do x=0., 1., 0.1
 ...
end do

How many iterations? That would be (under the rules of Fortran 90) MAX(INT((m2 – m1 + m3) / m3), 0) where (m1 is the start value (0.), m2 the stop value (1.) and m3 the step value (0.1)). Is that 10 or 11 (or even 9)? It depends entirely on your numeric representation: we recall that 0.1 may not be exactly representable as a real number and INT truncates in converting to integer. You'd also have to worry about repeated addition of real numbers.

So, use integers and do some arithmetic inside the loop

do y_loop = 0, 6
  y = 1 + y_loop/2.
  ...
end do

or

y = 1
do
  if (y>4) exit
  ...
  y = y+0.5
end do

Finally, you mention .f90 and .f95 file suffixes. gfortran doesn't take the first to mean that the source code follows the Fortran 90 standard (where the code would be fine). Further, the messages from the compiler are merely warnings, and these can be suppressed using the -std=legacy option. Conversely, using -std=f95 (or later standards) these become errors.


As a bonus fun fact consider the following piece of Fortran 90 code.

real y
integer i

loop_real: do y=1, 4, 0.5
end do loop_real

loop_integer: do i=1, 4, 0.5
end do loop_integer

While the loop named loop_real is valid, that named loop_integer isn't. In the calculation of the iteration count the three expressions are converted to the kind, with kind parameters, of the loop variable. INT(0.5) is 0.

Excisable answered 8/6, 2015 at 11:36 Comment(12)
But it has to be 10. Does not it? I don't think it fortran would evaluate that to 9 or 11.Vitrescent
0.1 is not exactly representable in many implementations. If the exact value is 0.9999 or 1.00001 you get different iteration counts from each other and from one where the exact value is indeed 0.1. Note that INT is defined with truncation, not nearest rounding.Excisable
[There's an out-by-one error above, also: the naive answer would be 11.]Excisable
If the .1 add rounds up slightly you get 10 iterations stopping at something slightly over 0.9. If its exact or slightly rounding down you get the expected 11 iterations. I don't see how it could ever be 9.Romelda
@Romelda my comment was indeed wrong. My outlandish point was that you don't know that "slightly". It would be a poor implementation, but it could happen. Other cases may be more extreme than this one.Excisable
When the did the ability to use real numbers as loop indices get added? I learned a little FORTRAN in the early 1980s (yay punchcards!) and I remember loop indices being restricted to ascending integers.Armijo
@supercat, in the 1980s FORTRAN had real loop control. It wasn't until Fortran 90 that real control was deleted. Fortran has never required 'ascending integers' (even now do i=5,1,-1 is valid control).Excisable
@francescalus: Was that the ability to use either negative indices or non-constant indices added in FORTRAN-77? Having the index direction be non-constant complicates the run-time code generation in ways that would for most purpose not be particularly advantageous. I recall learning that early FORTRAN compilers required that array-index expressions be intConst or intVar+intConst*intVar, but that was waived in FORTRAN-77. Maybe more versatile DO loops were added at that time?Armijo
@francescalus: BTW, I would think a language like FORTRAN could benefit from a looping syntax which allows one to specify one or more variables, each with a start value and pre-or-post step value, but which specifies the number of iterations as an integer. In many cases, application code will know the number of iterations more readily than it would know the ending loop value. If one knows the loop should run for n iterations starting at k and incrementing by s, being able to say that rather than specifying the loop as running from k to k+n*s-1 would make things easier...Armijo
...for both a human and a compiler, especially if s isn't constant, it could smoothly accommodate floating-point indices, and it would avoid degenerate behavior when s is zero or the floating-point step value is smaller too small to be added to the index.Armijo
@supercat, Fortran 66 required positives integers (variable or constant) for loop control, but the step could be greater than one. If you meant previously "ascending integers" to allow gaps then you were correct (but this was relaxed by the 1980s). Fortran 66, of course, had all loops having at least one iteration - because loops were essentially like i=i1; do while (i.lt.i2); ... i=i+i3; end do.Excisable
@francescalus: TI DSPs have an instruction that actually works a lot like a FORTRAN-66 DO loop; the word following the block-repeat instruction is the address of the last instruction of the loop, and the act of fetching from that address will load the program counter with the second address following the block-repeat instruction.Armijo

© 2022 - 2024 — McMap. All rights reserved.