This question already has answers here:
Preserve bounds in allocation in intrinsic assignment
(2 answers)
Fortran doesn't keep lower/upper array bounds after copy to another allocatable array
(2 answers)
Closed 4 months ago.
I am trying to test the Fortran 2003 feature that allows to add an element to an array. Consider the following code:
program test
implicit none
integer :: i
integer, parameter :: n=6, j=2
integer, allocatable :: inx(:)
open(3, file='check.dat')
allocate(inx(0:1)); inx=0
do i=0,1
write(3,*) i, inx(i)
end do
do i=1,n
inx=[inx,i+j]
end do
do i=0,n
write(3,*) i, inx(i)
end do
end program test
I get the following runtime error:
At line 22 of file test.f90
Fortran runtime error: Index '0' of dimension 1 of array 'inx' below lower bound of 1
I explicitly set inx(0:1), so that inx's index starts from zero ( I want inx(0:some number)) but it seems that's it's reallocating from 1?
Related
I have the following simple Fortran code
program test
type vec
integer :: x(3)
end type
type(vec) :: v(2)
call sub(v)
contains
subroutine sub (v)
class(vec), intent(in) :: v(:)
integer :: k, q(3)
q = [ (v(1)%x(k), k = 1, 3) ] ! <-- fails here
end subroutine
end program
which, when compiled by GNU Fortran 11 (but not other versions) with -fcheck=bounds, fails with the error
At line 19 of file test.f90
Fortran runtime error: Index '3' of dimension 1 of array 'v%_data%x' above upper bound of 2
It look as if the compiler simply interchanged the lengths of x and v and this can be confirmed by changing the numbers.
When the word class is replaced by type, the problem goes away.
I believe that the code is valid as it is. Or is it violating some Fortran language restriction that results in this surprising behaviour?
This question already has answers here:
Using matrices as arguments in functions and as output in subroutines in Fortran
(2 answers)
Function ‘array’ has no IMPLICIT type
(1 answer)
Closed 1 year ago.
I have a main function which creates an array and passes the array to a subroutine, the subroutine should then read in values to the array, my array has a size of 5 so the subroutine should have 5 numbers input into the array.
Here is my code currently:
program main
real arr(5)
c
call readData(arr)
stop
end
subroutine readData(arr)
c
do i=1, 5
read (*,*) arr(i)
end do
return
end
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
In Fortran 95, how would you write a function which takes an arbitrary matrix of known dimension as a argument ? I get the impression that not allocating the dimension doesn't work, even if the function only operates on matrices which have been previously allocated.
real, dimension (2, 4) :: mymatrix
test(mymatrix)
contains
function test(matrix)
real, dimension (: , :), intent(in) :: matrix
someothervariable = matrix(i, j)
return
end function test(matrix)
This works as long as you have an explicit interface. Putting the function as an internal procedure as you have it works, as does putting the procedure into a module. Consider this example:
program example
implicit none
real, dimension(2,4) :: matrixA
real, dimension(5,13) :: matrixB
integer :: matval
matval = test(matrixA)
print *, 'Test returned: ',matval
matval = test(matrixB)
print *, 'Test returned: ',matval
contains
function test(matrix)
implicit none
real, dimension(:,:), intent(in) :: matrix
integer :: test
print *, "matrix dimensions:"
print *, "i: ", lbound(matrix,1), ubound(matrix,1)
print *, "j: ", lbound(matrix,2), ubound(matrix,2)
test = ubound(matrix,1)*ubound(matrix,2)
end function test
end program example
The output of this program is:
matrix dimensions:
i: 1 2
j: 1 4
Test returned: 8
matrix dimensions:
i: 1 5
j: 1 13
Test returned: 65
You can see that none of the arrays are allocatable and arbitrary sized arrays can be passed to the function. The function is able to inspect the bounds of the array dimensions and can operate on the contents of the array. I had the function return a value based upon the array dimensions as an example.
The problems with your code fragment are that you are calling the function improperly and are not returning a value. Functions (in Fortran) must return values and the value must be assigned to a variable. See the differences in how I call the function in my example. If you do not want to return a value, use a subroutine instead of a function.
I was doing an svd decomposition of a square matrix A, with A=U S Vdag, and in the fortran code, the line reads
lwork = -1
call zgesvd( 'A', 'A', A%d, A%d, A%m, A%d, S, U%m, U%d, Vdag%m, Vdag%d,work, lwork, rwork, info )
lwork = int(work(1));deallocate(work); allocate(work(lwork))
call zgesvd( 'A', 'A', A%d, A%d, A%m, A%d, S, U%m, U%d, Vdag%m, Vdag%d,work, lwork, rwork, info )
When I compiled with gfortran, it went through with no error or warning. However when I run the program, it shows error with message:
" ** On entry to ZGESVD parameter number 11 had an illegal value "
I could not figure out what went wrong.
For reference, the definitions of the parameters:
type cmatrix
integer(4) d
complex(8), allocatable :: m(:,:)
end type
type (cmatrix) A,U,Vdag
allocate(A%m(dim,dim),U%m(dim,dim),Vdag%m(dim,dim))
A%d = dim; U%m = dim; Vdag%d = dim
real(8) S(dim)
Thanks in advance!
Xiaoyu
p.s. It should be mentioned that such a program runs smoothly when compiled with ifort, but gfortran gives an runtime error as shown above
--- Problem solved!
It seems that the issue lies in how ifortran and gfortran allocates memory. I defined in the code USV type which:
type USV
integer is_alloc
type (cmatrix) U,V
real(8), allocatable :: S(:)
end USV
When initializing by
type(USV) Test_usv(:)
allocate(Test_usv(3)),
the value of is_alloc is 0 using intel fortran compiler, while arbitrary number for gfortran. I need to use this value as a criterion for allocating U V matrices:
if (is_alloc.eq.0) then
allocate(U%m(dim,dim))
end if
The fundamental problem is not a difference between ifort and gfortran. Your approach to the initialization of the variables isn't valid Fortran. Unless you initialize a variable with a declaration, assignment statement, etc., its value is undefined. One way to fix this would be to add a default initialization to the type definition:
type USV
integer is_alloc = 0
type (cmatrix) U,V
real(8), allocatable :: S(:)
end USV
Another approach would be to not track the allocation status yourself and to rely upon the intrinsic function that Fortran provides for this purpose:
if (.NOT. allocated (U%m) ) allocate(U%m(dim,dim))
P.S. Best practice is not to rely upon specific numeric values for kinds. The kind values are arbitrary and are not necessarily the number of bytes of the type. Some compilers use the number of bytes, others don't. One method to specify the number of bytes and to have portable code is to use types provided by the ISO Fortran environment:
use, intrinsic :: ISO_FORTRAN_ENV
integer(int32) :: d
real(real64), allocatable :: S(:)
The types are named after the number of bits. A list of the available types is in the "Intrinsic Modules" chapter of the gfortran manual.
I can't tell what is wrong with this free form Fortran program. It does not correctly handle its command line arguments.
It works if I use a static array for the command line argument instead of an allocatable array.
Also, is this a good first Fortran program? Is this the type of problem for which Fortran would be useful? I already know C, C++, and a little bit of D.
module fibonacci
use ISO_FORTRAN_ENV
implicit none
contains
subroutine output_fibonacci(ordinal)
! Declare variables
integer, parameter :: LongInt = selected_int_kind (38)
integer, intent(in) :: ordinal
integer :: count
! integer (kind=LongInt) :: count, compare=2
integer (kind=LongInt), dimension(2,2) :: matrix, initial
matrix=reshape((/ 1, 1, 1, 0 /), shape(matrix))
initial=reshape((/ 1, 0, 0, 1 /), shape(initial))
count = ordinal
! Do actual computations
do while (count > 0)
! If the exponent is odd, then the output matrix
! should be multiplied by the current base
if (mod(count,2) == 1) then
initial = matmul(matrix, initial)
end if
! This is the squaring step
matrix = matmul(matrix, matrix)
count = count/2
end do
write (*,*) initial(1,2)
end subroutine output_fibonacci
end module fibonacci
program main
use, intrinsic :: ISO_FORTRAN_ENV
use fibonacci
implicit none
! The maximum allowed input to the program
integer :: max=200, i, size=20
character, allocatable :: argumen(:)
integer :: error, length, input
allocate(argumen(size))
! write(*,*) argcount
do i=1, command_argument_count()
call get_command_argument(i, argumen, length, error)
read(argumen,*,iostat=error) input
! write(*,*) argument
! write (*,*) input
if (error .ne. 0) then
write(ERROR_UNIT,'(I36.1,A)') input, "is not an integer"
stop (1)
else if (input > max) then
write(ERROR_UNIT,'(A,I36.1,A)') "Input ", input, " is too large"
stop (1)
end if
call output_fibonacci(input)
end do
end program
This line
character, allocatable :: argumen(:)
declares an allocatable array of characters. So the statement
allocate(argumen(size))
makes argumen an array of 20 single-character elements. That's not the usual way of dealing with strings in Fortran and argumen doesn't match (in type or rank) the requirements for the second argument in the call to get_command_argument.
Instead you should write
character(len=:), allocatable :: argumen
to declare argumen to be a character variable of allocatable length. In some contexts you can simply assign to such a variable, e.g.
argumen = 'this is the argument'
without having to previously allocate it explicitly.
With Intel Fortran v14 the call to get_command_argument compiles without warning but on execution the argument argumen isn't automatically allocated and it remains unassigned. I'm honestly not sure if this behaviour is standard-conforming or not. One approach would be to make two calls to get_command_argument, first to get the size of the argument, then to get the argument; like this
do i=1, command_argument_count()
call get_command_argument(i, length=length, status=error)
allocate(character(length)::argumen)
call get_command_argument(i, argumen, status=error)
! do stuff with argument
deallocate(argumen)
end do
Using the name length for the variable to be assigned the value returned by the optional argument called length is legal but a mite confusing. The deallocate statement ensures that argumen can be allocated again for the next argument.
I'll leave you the exercise of declaring, and using, an allocatable array of allocatable-length characters.
Disclaimer: the next two paragraphs contain material which some may find subjective. I will not be entering into any discussion about these parts of this answer.
Is this a good first Fortran program ? It's better than a lot of what I see here on SO. Personally I prefer the consistent use of the modern /= to .ne., < to .lt (etc), I don't use stop if I can avoid it (I usually can), and I'm sure I could find other nits to pick.
Is this the type of problem for which Fortran would be useful? Fortran is useful for all types of problem, though I admit it can be quite challenging using it to write a web server.