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.
Related
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?
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
All the below code are using -O3 -xHost (or -Ofast -march=native in gfortran) optimization.
example1
integer, parameter :: r8=selected_real_kind(15,9)
subroutine f(a,b,c)
real(kind=r8) :: a(1000), b(1000), c(1000)
c(:)=a(:)+b(:)
return
end
The above code should be vectorized,right? The real is real 8 type, it should took 64 bit in the ram. For AVX2 it is with 256 bit register or something, The above code is like doing c(1:4) = a(1:4) + b(1:4) in one clock cycle or something, and 4 is because 256/64=4.
But why do I frequently find that actually doing the loop is faster? see example 2,
example2
integer, parameter :: r8=selected_real_kind(15,9)
subroutine f(a,b,c)
real(kind=r8) :: a(1000), b(1000), c(1000)
integer :: i
do i=1,1000
c(i)=a(i)+b(i)
endddo
return
end
I notice that the compiler in example1 may complain that the array are not aligned or something. Therefore actually example2 is faster than example1.
But I mean in principle both example1 and 2 should be the same speed right? In example2, the compiler should be smart enough to vectorize the code correspondingly.
Finally, in the below code, example3, is there any vectorization?
example3
integer, parameter :: r8=selected_real_kind(15,9)
subroutine f(a,b,c)
real(kind=r8) :: a(1000), b(1000), c(1000)
c(:) = exp(a(:)) + log(b(:))
return
end
or slightly complicated things like, example4
example4
integer, parameter :: r8=selected_real_kind(15,9)
subroutine f(a,b,c)
real(kind=r8) :: a(1000), b(1000), c(1000)
c(:) = exp(a(:)) + log(b(:)) + exp(a(:)) * log(b(:))
return
end
I mean is vectorization is only for those very basic operatons like, op = + - * /
a(:) = b(:) op c(:)
However, for something more complicated, like
a(:) = log(b(:) + c(:)*exp(a(:))*ln(b(:)))
Then vectorization may not work?
It seems in many case using a do loop is faster than writing things like a(:)=b(:)+c(:). It seem the compiler are doing very good job or highly optimized in just doing the do loops.
This question already has answers here:
How to pass array to a procedure which is passed as an argument to another procedure using Fortran
(2 answers)
Closed 1 year ago.
I'm writing a subroutine that can take function names are argument.
In my example, it is call call_test(ga), where ga is a function ga(x).
My old practice works fine if x is a scalar.
The problem is the program failed if x is an array.
The minimal sample that can reproduce the problem is the code below:
module fun
implicit none
private
public :: ga, call_test
contains
subroutine call_test(fn)
double precision,external::fn
double precision::f
double precision,dimension(0:2)::x0
x0 = 0.111d0
print*,'Input x0=',x0
print*,'sze x0:',size(x0)
f = fn(x0)
print*,'fn(x0)=',f
end subroutine call_test
function ga(x) result(f)
double precision,dimension(0:) :: x
double precision::f
print*,'size x inside ga:',size(x)
print*,'x in ga is:=',x
f = sum(x)
end function ga
end module
program main
use fun
call call_test(ga)
end program main
Using latest ifort, my execution result is:
Input x0= 0.111000000000000 0.111000000000000 0.111000000000000
sze x0: 3
size x inside ga: 140732712329264
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
a.out 000000010C6EC584 Unknown Unknown Unknown
libsystem_platfor 00007FFF20610D7D Unknown Unknown Unknown
a.out 000000010C6C62B2 _MAIN__ 32 main.f90
a.out 000000010C6C5FEE Unknown Unknown Unknown
Using gfortran the result is
Input x0= 0.11100000000000000 0.11100000000000000 0.11100000000000000
sze x0: 3
size x inside ga: 0
x in ga is:=
fn(x0)= 0.0000000000000000
My question is why is this, and how to make it work. A functional code solution based on my code is highly appreciated.
#IanBush is right in his comment. You need an explicit interface as the function argument takes an assumed-shape dummy argument. Since you have some other deprecated features in your code, here is a modern reimplementation of it in the hope of improving Fortran community coding practice,
module fun
use iso_fortran_env, only: RK => real64
implicit none
private
public :: ga, call_test
abstract interface
function fn_proc(x) result(f)
import RK
real(RK), intent(in) :: x(0:)
real(RK) :: f
end function fn_proc
end interface
contains
subroutine call_test(fn)
implicit none
procedure(fn_proc) :: fn
real(RK) :: f
real(RK) :: x0(0:2)
x0 = 0.111_RK
write(*,"(*(g0,:,' '))") 'Input x0 =',x0
write(*,"(*(g0,:,' '))") 'sze x0:',size(x0)
f = fn(x0)
write(*,"(*(g0,:,' '))") 'fn(x0) =', f
end subroutine call_test
function ga(x) result(f)
real(RK), intent(in) :: x(0:)
real(RK) :: f
write(*,"(*(g0,:,' '))") 'size x inside ga:',size(x)
write(*,"(*(g0,:,' '))") 'x in ga is:',x
f = sum(x)
end function ga
end module
program main
use fun
call call_test(ga)
end program main
Note the use of the abstract interface. The import statement merely imports the symbol RK for usage within the abstract. Without it, you will have to use iso_fortran_env to declare RK as real64. Do not use double precision, it is deprecated and does not necessarily mean 64bit real number. Also, note the conversion of 0.111d0 to 0.111_RK. Also, I strongly recommend not using single-letter variable names. They are ugly, error-prone, and non-informative. Modern Fortran allows variable names up to 63 characters long. There is no harm in having long but descriptive variable names. Here is the code output,
$main
Input x0 = 0.11100000000000000 0.11100000000000000 0.11100000000000000
sze x0: 3
size x inside ga: 3
x in ga is: 0.11100000000000000 0.11100000000000000 0.11100000000000000
fn(x0) = 0.33300000000000002
I have a small code declaring a pointer to array of derived type which has a field that is an allocatable array of another derived type having a real variable as a field.
Using gnu fortran (8.2) I obtain different results for each location in the array or as a vector.
Using intel fortran (2019.4) compiler succeeded.
program test
implicit none
integer, parameter :: length = 2
real(8), dimension(length) :: a, b
integer :: i
type point
real(8) :: x
end type point
type stored
type(point), dimension(:), allocatable :: np
end type stored
type(stored), dimension(:), pointer :: std=>null()
allocate(std(1))
allocate(std(1)%np(length))
std(1)%np(1)%x = 0.3d0
std(1)%np(2)%x = 0.3555d0
do i = 1, length
write(*, "('std(1)%np(',i1,')%x = ',1e22.14)") i, std(1)%np(i)%x
end do
do i = 1, length
write(*, "('std(1)%np(1:',i1,') = ',2e22.14)") i, std(1)%np(1:i)%x
end do
a = std(1)%np(1:2)%x
b = [std(1)%np(1)%x, std(1)%np(2)%x]
if (norm2(a - b) .gt. 1d-3) then
write(*,*) 'failure'
else
write(*, *) 'success'
end if
end program test
the code terminates successfully, but using gfortran one obtains 'failure' on screen and inconsistent prints above and using Intel compiler one obtains 'success' on screen and consistent prints above.
It's not clear to me what your question is, unless it's the title. If so, no, pointers to derived types are fine. Your program correctly allocates std as an extent-1 array and then allocates std(1)%np(2). It then assigns to the x subcomponents of both np elements. Looks fine to me.
There are several things that could potentially cause "failure" - you should run the gfortran code in the debugger to see what is going wrong.
The problem presented in the code above was resolved in the following [link] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91077
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.