I have "inherited" a simple congruential pseudo-random-number generator that looks like this:
subroutine ribm(rndm,ial)
implicit none
integer :: ial
real :: rndm, al
ial=ial*65539
if(ial.lt.0) then
ial=ial+2147483647+1
endif
al=ial
rndm=al*0.4656613e-9
end subroutine ribm
The ial variable contains the RNG seed and it is initialised once outside the generator. The generator is supposed to produce pseudo-random numbers between 0 and 1, as usual. Therefore, ial must always stay non-negative. The code tries to enforce this condition using the if statement.
I test the generator using the following program:
program testribm
implicit none
real :: r
integer :: i
data i /12345/
call ribm(r,i)
call ribm(r,i)
call ribm(r,i)
call ribm(r,i)
call ribm(r,i)
call ribm(r,i)
print *,r,i
contains
subroutine ribm(rndm,ial)
! [...]
end subroutine ribm
end program testribm
If I compile with gfortran v4.8.2 with optimisation -O1 or lower, I get:
0.580895185 1247462939
OTOH, if I use -O2 I get:
-0.709615409 -1523887535
Note the negative seed value. Optimisation affects the integer arithmetics and the final result of the repeated calls to ribm.
I know how to work around/fix this problem. My question is: is this a gfortran bug? Or is this behaviour due to the fact that the code is non-standard? But if this is the case, shouldn't gfortran produce some warning message?
Optimization can change the actual calculations done. Don't be surprised if the results change for a non-standard calculation, such as one that involves integer overflow. My suggestion to implement algorithms in Fortran that use unsigned integers is to use the next-larger integer type. e.g., if the algorithm should be done with unsigned 32-bit integers, use Fortran's signed 64-bit integer.
I would add to M.S.B.'s answer, that the problem occurs only when the compiler optimizes several calls to ribm in one go. (My previous suggestion was invalid.)
But the answer to the original question. I don't think it's a compiler bug. 2147483647+1 is simply out of range. The question is why there is no warning even with -pedantic -Wall -Wextra. It turns out, pointed out by #Arek' Fu that one needs -Wstrict-overflow, whis is included only as -Wstrict-overflow=1 in -Wall.
Where possible, I recommend using functions iand, ior, ieor, ishft and similar for portable results, instead of arithmetic.
both answers are nice, as for a solution, I would think using parenthesis is the right way to go to prevent the compiler optimizing away?
subroutine ribm(rndm,ial)
implicit none
integer :: ial
real :: rndm, al
ial=ial*65539
if(ial.lt.0) then
ial=(ial+1)+2147483647
endif
al=ial
rndm=al*0.4656613e-9
end subroutine ribm
Related
I'm relatively new using the Fortran language and I'm dealing with a pre-written program that I have to make some changes, and I have all 8 bytes variables declared as REAL(8) on the program's statement area. However, when attributing numerical values to the variables and/or arrays, the original program's author always uses something like:
...
REAL(8) A
A = 1.d0
...
Is that strict necessary given that 'A' is declared not as DOUBLE PRECISION, but literally as REAL(8), even thought -- I think -- both have the same KIND?
Furthermore, I have read somewhere that the use of REAL(8) should be abandoned? Is that so? Why?
As far as I know (and I certainly can be wrong), the number of bytes used in a DOUBLE PRECISION variable is dependent of the compiler, making it dangerous (I assume) or at least undesirable its use in place of REAL(8), if my intention is to declare an 8 bytes variable.
(I am working with Fortran 90/95)
I would gratefully receive comments to clarify this issue! Thanks a lot!
I want to write a piece of code that can find all of the available integer kinds of my machine and print the range for all of them.
Finding the kinds was not the hard part, using selected_int_kind I was able to iterate over all of the available kind number till I got a -1 value that indicated that the integer was not longer representable by the compiler.
This process resulted in an array of the available kind number for example (/ 1 2 4 8 16/) (this was the result for my gfortran compiler)
The next step is to use this array to define 5 different kinds of integers and ask for what the maximum representable integer is.
My idea was to use an allocatable integer and allocate it every time with an other kind parameter, something like
program main
integer,allocatable :: i
integer::j
integer,dimension(:)::nb_kind
call give_me_the_kinds(nb_kind)
for j=1,size(nb_kind)
allocate(i,kind=nb_kind(j))
print *,huge(i)
deallocate(i)
end program
But this did not work out for me. Has anybody has some experience with this? I think it could be done but I'm not sure how to do it.
Dynamically-typed variables (going from a kind number to the variable directly) are not possible in Fortran. Kind numbers have to be compile-time constant. What you can do is this:
program main
use iso_fortran_env, only : integer_kinds
implicit none
integer :: i
open(20,file="mykinds.f90",status="unknown",action="write")
write (20,'(A/A)') 'program main',' implicit none'
do i=1, size(integer_kinds)
write (20,'(A,I0,A,I0,A)') ' integer(kind=',integer_kinds(i),') :: i',i
end do
do i=1, size(integer_kinds)
write (20,'(A,I0,A,I0,A)') ' write (*,"(A,I0)") "integer(kind=',&
& integer_kinds(i),') huge = ", huge(i',i,')'
end do
write (20,'(A)') 'end'
close(20)
call execute_command_line ("gfortran mykinds.f90 && ./a.out")
end program main
I have a Fortran program which uses a routine in a module to resize a matrix like:
module resizemod
contains
subroutine ResizeMatrix(A,newSize,lindx)
integer,dimension(:,:),intent(inout),pointer :: A
integer,intent(in) :: newSize(2)
integer,dimension(:,:),allocatable :: B
integer,optional,intent(in) :: lindx(2)
integer :: i,j
allocate(B(lbound(A,1):ubound(A,1),lbound(A,2):ubound(A,2)))
forall (i=lbound(A,1):ubound(A,1),j=lbound(A,2):ubound(A,2))
B(i,j)=A(i,j)
end forall
if (associated(A)) deallocate(A)
if (present(lindx)) then
allocate(A(lindx(1):lindx(1)+newSize(1)-1,lindx(2):lindx(2)+newSize(2)-1))
else
allocate(A(newSize(1),newSize(2)))
end if
do i=lbound(B,1),ubound(B,1)
do j=lbound(B,2), ubound(B,2)
A(i,j)=B(i,j)
end do
end do
deallocate(B)
end subroutine ResizeMatrix
end module resizemod
The main program looks like:
program resize
use :: resizemod
implicit none
integer,pointer :: mtest(:,:)
allocate(mtest(0:1,3))
mtest(0,:)=[1,2,3]
mtest(1,:)=[1,4,5]
call ResizeMatrix(mtest,[3,3],lindx=[0,1])
mtest(2,:)=0
print *,mtest(0,:)
print *,mtest(1,:)
print *,mtest(2,:)
end program resize
I use ifort 14.0 to compile the codes. The issue that I am facing is that sometimes I don't get the desired result:
1 0 0
1 0 5
0 0 -677609912
Actually I couldn't reproduce the issue (which is present in my original program) using the minimal test codes. But the point that I noticed was that when I remove the compiler option -fast, this problem disappears.
Then my question would be
If the pieces of code that I use are completely legal?
If any other method for resizing the matrices would be recommended which is better than the one presented in here?
The relevance of the described issue and the compiler option "-fast".
If I've read the code right it's legal but incorrect. In your example you've resized a 2x3 array into 3x3 but the routine ResizeMatrix doesn't do anything to set the values of the extra elements. The strange values you see, such as -677609912, are the interpretation, as integers. of whatever bits were lying around in memory when the memory location corresponding to the unset array element was read (so that it's value could be written out).
The relevance of -fast is that it is common for compilers in debug or low-optimisation modes, to zero-out memory locations but not to bother when higher optimisation is switched on. The program is legal in the sense that it contains no compiler-determinable syntax errors. But it is incorrect in the sense that reading a variable whose value has not been initialised or assigned is not something you regularly ought to do; doing so makes your program, essentially, non-deterministic.
As for your question 2, it raises the possibility that you are not familiar with the intrinsic functions reshape or (F2003) move_alloc. The latter is almost certainly what you want, the former may help too.
As an aside: these days I rarely use pointer on arrays, allocatable is much more useful and generally easier and safer too. But you may have requirements of which I wot not.
I have done a lot of work with array-based interpreted languages, but I'm having a look at Fortran. What has just occurred to me after writing my first bit of code is the question of whether or not gfortran will optimise an expression using array syntax by placing the expression in a single loop. In most array-based interpreters an expression such as A=B/n*2*pi (where B is an array) would require 5 loops and multiple array temporaries to evaluate. Is gfortran clever enough to optimise this out, and will my code below (the line that calculates the array from 0 to 2pi) be as efficient as an explicit do loop around the expression? Is there anything I should look out for when using array syntax if I'm worried about performance?
PROGRAM Sine
IMPLICIT NONE
REAL, PARAMETER :: PI = 3.415926535
INTEGER, PARAMETER :: z = 500
INTEGER :: ier
INTEGER, EXTERNAL :: PGBEG
REAL, DIMENSION(z) :: x,y
x=(indgen(z)-1.0)/z*(2*pi) ! This line...``
y=sin(x)
CALL plot(y,x)
CONTAINS
FUNCTION indgen(n) result(i)
INTEGER :: n
INTEGER, DIMENSION(n) :: i
INTEGER :: l
DO l=1,n
i(l)=l
END DO
END FUNCTION indgen
SUBROUTINE plot(y,x)
REAL, DIMENSION(:) :: x,y
ier=PGBEG(0,'/XWINDOW',1,1)
CALL PGENV(0.0,7.0,-1.0,1.0,0,1)
CALL PGLINE(SIZE(x),x,y)
CALL PGEND()
END SUBROUTINE plot
END PROGRAM Sine
In gfortran you can use the -Warray-temporaries flag to see all array temporaries generated. When I try your example no extra array temporary is generated (other than the one necessary to store the results of indgen(z)), so I guess gfortran is clever enough.
The expression z*(2*pi) is a compile-time constant, which the compiler can easily verify, so that should not be evaluated at run time regardless. Additionally, virtually all modern compilers should perform one-line "elemental" array operations within a single loop, and in many cases SIMD instructions will be generated (auto-vectorization).
Whether a temporary is generated usually depends on whether or not each element can be handled independently, and whether or not the compiler can prove this. Xiaolei Zhu's suggestion of using -Warray-temporaries is a good one. Don't mix this up wih -fcheck=array-temps, which I think only applies to temporaries generated for function calls.
Here's an example of such a message from gfortran:
foo.F90:4.12:
foo(1:20) = 2*foo(20:1:-1)
1
Warning: Creating array temporary at (1)
Your function call will be done in a separate loop, unless the compiler can inline it. Whether or not the compiler inlines a short function can be pretty unpredictable; it potentially depends on where that other function is defined, whether or not the function has the pure attribute (although in practice this rarely seems to matter), the vendor and version of the compiler itself, and the options you pass. Some compilers can generate a report for this; as I recall, the Intel compiler has a decent one.
Edit: It's also possible to inline the expression in this line pretty easily by hand, using an "implied do loop":
x = [ ( real(i)/z*(2*pi), i = 0, z-1) ]
Yes.
Fortran is compiled rather than interpreted.
It handles loops very well.
I'm trying to incorporate error checking within a pure procedure I am writing. I would like something like:
pure real function func1(output_unit,a)
implicit none
integer :: a, output_unit
if (a < 0) then
write(output_unit,*) 'Error in function func1: argument must be a nonnegative integer. It is ', a
else
func1 = a/3
endif
return
end function func1
However, pure functions are not allowed to have IO statements to external files, so I tried passing a unit number to the function, e.g. output_unit = 6, which is the default output. gfortran still regards this as illegal. Is there a way around this? Is it possible to make the function a derived type (instead of intrinsic type real here) which outputs a string when there is an error?
You are not the first person to have this problem, and I'm happy to say that this flaw in the standard will be remedied in Fortran 2015. As stated in this document (page 6, header "Approved changes to the standard"), "the restriction on the appearance of an error stop statement in a pure procedure should be removed".
The Fortran 2008 standard included the error stop statement in the context of some new parallel computing features. It signals an error and makes all processes stop as soon as is practicable. Currently, neither stop nor error stop statements are allowed in pure procedures, because they're obviously not thread-safe. In practice this is unnecessarily restrictive in cases where an internal error occurs.
Depending on your compiler, you may have to wait patiently for the implementation. I know that Intel has implemented it in their ifort compiler. ("F2015: Lift restriction on STOP and ERROR STOP in PURE/ELEMENTAL procedures")
alternative
For an alternative approach, you could have a look at this question, though in you case this is probably slightly trickier as you have to change the do concurrent keyword, not just pure.
(end of proper answer)
if getting dirty hands is an option ...
In the meantime you could do something brutal like
pure subroutine internal_error(error_msg)
! Try hard to produce a runtime error, regardless of compiler flags.
! This is useful in pure subprograms where you want to produce an error,
! preferably with a traceback.
!
! Though far from pretty, this solution contains all the ugliness in this
! single subprogram.
!
! TODO: replace with ERROR STOP when supported by compiler
implicit none
character(*), intent(in) :: error_msg
integer, dimension(:), allocatable :: molested
allocate(molested(2))
allocate(molested(2))
molested(3) = molested(4)
molested(1) = -10
molested(2) = sqrt(real(molested(1)))
deallocate(molested)
deallocate(molested)
molested(3) = molested(-10)
end subroutine internal_error
Should anyone ask, you didn't get this from me.
I've found an answer myself, detailed here. It uses what is considered "obsolescent", but still does the trick; it is called alternate return. Write the procedure as a subroutine as it doesn't work on functions.
pure real subroutine procA(arg1)
implicit none
integer :: arg1
if (arg < 0) then
return 1 ! exit the function and go to the first label supplied
! when function was called. Also return 2, 3 etc.
else
procA = ... ! whatever it should do under normal circumstances
endif
endsubroutine procA
....
! later on, procedure is called
num = procA(a, *220)
220 write(6,*) 'Error with func1: you've probably supplied a negative argument'
What would probably be better is what eriktous suggested--get the procedure to return a status, perhaps as a logical value or an integer, and get the program to check this value every time after it calls the procedure. If all's well, carry on. Otherwise, print a relevant error message.
Comments welcome.