Fortran. Which of the code shown below is right? - fortran

I have found out next interesting thing within Fortran. It's shown below in code sample.
I can't understand and have found nothing why the code at labels 10 and 12 works and at 11 and 13 doesn't.
implicit none
integer :: i
integer :: IA(8) = [(i, i=1,8)]
integer :: IP
IP = 5
10 IA(IP:2) = [11, 12] ! works
11 IA(5:2) = [11, 12] ! doesn't work
12 print *, IA(IP:IP+1) ! works
13 print *, IA(IP:2) ! doesn't work
What is the difference?

Both versions of the statement labelled 10 and 11 are wrong.
The array section ia(5:2) is an array section consisting of zero elements of the array ia. The array section ia(IP:2) (when IP is a variable with value 5) is the same.
When using a literal constant in the array element subscripts your compiler knows when compiling that it can check the shape of the left- and right-hand sides match. Your compiler here has determined that ia(5:2) is of shape [0] and [11, 12] is of non-comformable shape [2]. It therefore reports the error.
Your compiler isn't detecting at compile time the error with non-constant subscripts in ia(IP:2). The code however violates the Fortran standard in exactly the same way. The seemingly correct output you see is bad luck.
Your compiler may not be detecting the error at run-time either because of the options you have used to compile or because it doesn't (correctly) apply the test of shape.
Other compilers may well complain, such as with the message:
Rank 1 of constant array operand has extent 2 instead of 0
Program terminated by fatal error
Abort (core dumped)
With the statement
print *, IA(IP:2)
this does "work" (in an otherwise correctly formed program). However, it suffers from exactly the same misunderstanding as before.
This print statement prints out zero array elements of ia in contrast to the two elements ia(5:6). Instead of "not working", the lack of obvious output is correctly printing nothing/a blank line.
In conclusion, ia(5:2) isn't a reference to the two elements after and including ia(5). For that you'd need ia(5:6), or ia(ip:ip+1). The subscripts are both bounds, not a bound and a count.

Related

Fortran's findloc with character type

I'm confused by the findloc intrinsic with a character array.
The program
print *, findloc(['AB'],'A',dim=1)
end
outputs
1
while I expected 0.
I thought that findloc searched for equality, and 'A' /= 'AB'.
If I make the scalar value of equal type as the array, then I do get what I expected: findloc(['AB'],'A ',dim=1) gives 0.
Note that findloc(['BA'],'A',dim=1) does give 0, so I don't think that findloc uses the index function.
I'm using ifort 18.0.3 on centos 7.
I agree that this is a bug in Intel Fortran's findloc() implementation. I created an Intel bug report to our developers.

gfortran Error: Integer too big for its kind at (1) [duplicate]

This question already has an answer here:
Fortran: Integer too big for its kind
(1 answer)
Closed 7 years ago.
I want to see integer kind number of gfortran
so I write this line
write(*,"(1X,I20,'correspond to kind ',I2)"),11111111111,kind(11111111111)
There will be compilation error says
precision of type test.f90:67:57: Error: Integer too big for its kind
at (1). Th is check can be disabled with the option -fno-range-check
So I tried recompile with -fno-range-check. But it gives result
-1773790777correspond to kind 4
What is wrong? On the other hand, intel fortran gives no error and correct answer
An integer literal without any kind designation is always of the default kind no matter what value you enter1. There is therefore no much sense to even inquire
kind(111111111111)
the kind of any such literal is always the default kind, provided the value is valid. So the same as kind(1).
All integer kinds have a limited range of values. The largest one you can get using
write(*,*) HUGE(1)
Here instead of 1 you can use any other constant or variable of the integer kind you examine. Most often, the default value of HUGE will be 2147483647 which corresponds to 32-bit integers.
To use larger integer literal constants, use larger non-default kinds.
It doesn't matter if you use the methods from Fortran 90:
integer, parameter :: lk = selected_int_kind(15)
write(*,*) 11111111111_lk
or from Fortran 2008
use iso_fortran_env
integer, parameter :: lk = int64
write(*,*) 11111111111_lk
Both will work. Of course kind(11111111111_lk) will return the value of lk.
1 That is in standard Fortran. Some compilers may promote a large value to a larger kind for you, but only as a non-standard extension. You may be unpleasantly surprised when moving to a compiler, which keeps the standard behaviour.
There may be a better explanation, but this is how I understand it. The short answer is the compiler defaults to a 4 byte integer.
Fortran is statically typed and you have not declared a variable type. The compiler is forced to use the default integer kind, 4 bytes in this case. The kind function simply returns the 'kind' of integer used. The compiler is letting you know that you are trying to assign a value too large for a 4 byte integer. When you apply -fno-range-check the compiler ignores this fact and the value overflows, thus the negative value returned. You can specify that the default integer kind be 8 bytes, -fdefault-integer-8. See the gfortran docs
Example foo.f90:
program foo
write(*,"(1X,I20,' correspond to kind ',I2)"),111111111111,kind(111111111111)
write(*,"(1X,I20,' correspond to kind ',I2)"),11,kind(11)
end program foo
Compiled with:
$ gfortran -fdefault-integer-8 -o foo.exe foo.f90
$ foo
Results in:
111111111111 correspond to kind 8
11 correspond to kind 8
So you can see the compiler is indifferent to the actual value you are testing.
However, I don't think this gets at the root of what you are trying to do, which I assume is to discover the minimum size of integer necessary for a specific numeric value. I don't know of a way to do this off hand with fortran. See this here and here for solutions you might be able to port from C. The second approach looks promising. In a dynamically typed language like Python the type assignment is handled for you.
>>> type(111111111111)
<type 'long'>
>>> type(11111)
<type 'int'>

Fortran DO loop, warning to use integer only

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
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.

Zero sized arrays and array bounds checking

When compiled with either GNU Fortran (v4.4.3) or Sun Studio F95 (v8.3) and no array bounds checking the following program runs without error. However, when array bounds checking is switched on (gfortran -fbounds-check and f95 -C, respectively) the GNU compiled executable runs again without error, whereas the Sun Studio compiled executable gives the run-time error,
****** FORTRAN RUN-TIME SYSTEM ******
Subscript out of range. Location: line 44 column 20 of 'nosize.f90'
Subscript number 2 has value 1 in array 't$27'
That's an error in the call to sub2(), which uses an automatic array dummy argument for x. The sub1() calls run fine with either compiler and any flags.
To my knowledge this program is "legal", in that a zero sized array may be referenced like a non-zero sized array, and there is no explicit indexing of the zero length dimension of x. But is there some zero sized array slicing or automatic array subtlety that I'm missing here? And should I expect array bounds checking to behave the same across different compilers, or should I consider it a vendor-specific extension?
MODULE subs
IMPLICIT NONE
CONTAINS
SUBROUTINE sub1(x)
IMPLICIT NONE
REAL :: x(:,:)
PRINT*,'------------------------------------'
PRINT*,SHAPE(x)
PRINT*,SIZE(x)
END SUBROUTINE sub1
SUBROUTINE sub2(n1,n3,x)
IMPLICIT NONE
INTEGER,INTENT(in) :: n1, n3
REAL :: x(n1,n3)
PRINT*,'------------------------------------'
PRINT*,SHAPE(x)
PRINT*,SIZE(x)
END SUBROUTINE sub2
END MODULE subs
PROGRAM nosize
USE subs
IMPLICIT NONE
INTEGER :: n1 = 2, n2 = 2, n3 = 0
REAL,ALLOCATABLE :: x(:,:,:)
ALLOCATE(x(n1,n2,n3))
x(:,:,:) = -99.9
PRINT*,'ALLOCATED? ',ALLOCATED(x)
PRINT*,'SHAPE =',SHAPE(x)
PRINT*,'SIZE =',SIZE(x)
PRINT*,'X =',x
CALL sub1(x(:,1,:))
CALL sub2(n1,n3,x(:,1,:))
END PROGRAM nosize
It doesn't give any problems with intel's fortran compiler with -check bounds; and IBM's xlf, which in my experience is extremely strict, also didn't complain with -qcheck.
But more broadly, yes, there's no standard about what bounds checking should or shouldn't do. I can certainly see why some compilers would flag an assignment to a zero-length array as being bad/wrong/weird; it is a strange corner-case.

Fortran compile error

I tried to compile a fortran program for soil-plant-atmosphere model, but I can't compile it under Ubuntu, it keeps giving me the error message like this:
f77 -c -o o/cupin2.o src/cupin2.f
src/cupin2.f: In subroutine `reflt':
src/cupin2.f:742:
dimension tairgl,eairgl,windgl,psisgl,hsoil,ecpy,hcpy
^
Invalid form for DIMENSION statement at (^)
make: ***
[o/cupin2.o] Error 1
Can anyone help me with this. Thanks.
Complete source code is here:Source Code
The DIMENSION statement is used to dimension arrays - so you have to specify the array dimensions. For example:
dimension tairgl(100),eairgl(20,50), ...
You don't actually need the DIMENSION statement, however, you could also say something like:
real tairgl(100)
integer eairgl(20,50)
You don't say whether this is your edit or whether someone else has written the code. The DIMENSION statement is described in:
http://en.wikipedia.org/wiki/Fortran_language_features
for example:
INTEGER, DIMENSION(0:100, -50:50) :: map
It expects array bounds after it. It's rather outdated and normally replaced by the type (e.g. REAL and the array bounds).
If you have inherited the code (and if it's got a long history) it's possible it has some syntax which is now non-standard but still compiles on some machines. If you are actively editing the code you will need to learn some FORTRAN.
UPDATE from a previous question the OP appears to have deleted the array bounds from a syntactically correct dimension statement.