how to make fortran random number [duplicate] - random

This question already has answers here:
Overflow in a random number generator and 4-byte vs. 8-byte integers
(2 answers)
Closed 2 years ago.
I wanna make rand number without using functions
PROGRAM RTEST
PARAMETER (N=100)
IMPLICIT REAL(A-H,O-Z), INTEGER(I-N)
DIMENSION A(N)
OPEN(99,FILE='RANDOM.DAT',FORM='FORMATTED')
IBMO=3149
SUM=0.0
DO 5 I=1,N
IBMO=IBMO*65549
IF(IBMO) 101, 102, 102
101 IBMO=IBMO+2147483647+1
102 RANDOM=0.46566128E-9*IBMO
A(I)=RANDOM
WRITE(99,10)I,A(I)
WRITE(6,10) I,A(I)
10 FORMAT(5X,I4,3X,F12.7)
SUM=SUM+A(I)
AVE1=SUM/FLOAT(N)
20 FORMAT(12X,F12.7)
30 FORMAT(5X,I4,3X,F12.7)
WRITE(6,20) AVE1
WRITE(99,30)I,AVE1
5 CONTINUE
CLOSE(99)
AVE=SUM/FLOAT(N)
WRITE(6,*)AVE
PAUSE
STOP
END
but i always got integer overflow or invalid floating point error.....
so what my think was type error
i try to change real >> real*8
and integer >> integer*8
but every try was fail....
what is problem?

Your issue is that you need even constants to have a specific type.
Here's what you need to do:
PROGRAM RTEST
USE, INTRINSIC :: ISO_FORTRAN_ENV, ONLY: int64, real64
IMPLICIT NONE
INTEGER, PARAMETER :: N = 100
REAL(KIND=real64) :: A(N)
INTEGER(KIND=int64) :: IBMO
...
IBMO = IBMO * 65549_int64
IBMO = IBMO + 2147483648_int64
and so on. The appended _int64 (after you have imported it from the iso_fortran_env module) tells the compiler to treat this number as a 64-bit integer. Instead of the line use, intrinsic :: iso_fortran_env you can also use the line
INTEGER, PARAMETER :: int64 = selected_int_kind(19)
INTEGER, PARAMETER :: real64 = selected_real_kind(r=300)
(after the IMPLICIT NONE, of course.)
That said, is there a reason you're using such antiquated Fortran syntax?
Any Fortran program that doesn't include the line implicit none is suspicious. Then you're using the syntax
do 5 i = 1, n
...
5 continue
What's wrong with
do i = 1, n
...
end do
And then
if (ibmo) 101, 102, 102
That's syntax I don't even recognise.

Related

Broken GFortran double precision in numerical multiplications and divisions? [duplicate]

This question already has an answer here:
Precision not respected
(1 answer)
Closed 1 year ago.
I run a gfortran code for multiplication and division and they give me different results when compared to results by c++,c etc. All use double precision. I believe that double precision I use in fortran is not correct or it is broken... I've checked numbers with calculator and fortran seems to create some numbers in the near end of decimals... Below is the code in gfortran,
PROGRAM problem
!-----------------------------------------------------------------------
integer, parameter :: dp = selected_real_kind(15,307)
real(dp) :: answer,w
open(1, file = 'problem.txt')
w=0.99
answer=w
do i = 10, 0, -1
answer = answer*w
write (*,"(E18.9)",advance="yes") answer
!-print results to text file
write (1,"(E18.9)",advance="yes") answer
end do
write(*,*) "Done."
close(1)
END PROGRAM problem
gfortran results are,
0.980100019E+00
0.970299028E+00
0.960596047E+00
0.950990096E+00
0.941480204E+00
0.932065411E+00
0.922744766E+00
0.913517327E+00
0.904382162E+00
0.895338349E+00
0.886384974E+00
my calculator shows,
0.9801
0.970299
0.96059601
0.950990049
Am I missing something in variable type declaration or is it intrinsic in gfortran?
Although you've declared w to be double precision, you've initialised it to 0.99, which is only a single-precision constant. In order to initialise w as a double precision constant, you need w = 0.99_dp.

Generating different sequence of random numbers in Fortran 95 for every run [duplicate]

I am trying to compile the following simple code using Gfortran 4.7 from mac-ports (OS-X):
program main
implicit none
integer :: n = 1, clock, i
integer, dimension(1) :: iseed
! initialize the random number generator
call random_seed(size = n)
call system_clock(COUNT=clock)
iseed = clock + 37 * (/ (i - 1, i = 1, n) /)
! iseed = clock
! iseed = abs( mod((clock*181)*((1-83)*359), 104729) )
call random_seed(PUT = iseed)
end program main
and have this error:
gfortran-mp-4.7 tmp.f90
tmp.f90:17.23:
call random_seed(PUT = iseed)
1
Error: Size of 'put' argument of 'random_seed' intrinsic at (1) too small (1/12)
I don't use Fortran at all (I am a C++ guy), so would really appreciate if someone could help and make it working.
p.s. On a similar issue i found couple of forum posts, the current uncomment solution is similar to the one mentioned in this GCC bug report.
The one with abs is mentioned in this stack overflow post (added it without PID since i don't run in parallel anyway.
UPDATE:
the following works:
program main
implicit none
integer :: n = 12, clock, i
integer, dimension(:), allocatable :: iseed
! initialize the random number generator
allocate(iseed(n))
call random_seed(size = n)
call system_clock(COUNT=clock)
iseed = clock + 37 * [(i, i = 0,n-1)]
call random_seed(PUT = iseed)
end program main
To amplify somewhat on #Yossarian's comment, this
call random_seed(size = n)
returns, in n, the size of the rank 1 integer array that you have to use if you want to initialise the RNG. I'd suggest making iseed allocatable by changing its declaration to:
integer, dimension(:), allocatable :: iseed
then, after getting a value for n, allocate it:
allocate(iseed(n))
populate it with your favourite values, then put it.
You might be able to allocate and populate it in one statement like this:
allocate(iseed(n), source = clock + 37 * [(i, i = 0,n-1)])
I write might because this depends on how up to date your compiler is.
EDIT, after OP comment
No, you have not quite understood what I suggested.
Get a value for n by executing
call random_seed(size = n)
don't initialise n to 12.
Then allocate the array and populate it, either in one statement (using sourced allocation) or an allocate statement followed by an assignment.
In
allocate(iseed(n))
call random_seed(size = n)
the sequence of operations is incorrect. This sets iseed to have 12 elements (which is the value of n when the first statement is executed), and then sets n to the size of the array required by the RNG. So long as that is 12 you won't see any problems, but as soon as you port your code to another compiler, possibly even another version of the same compiler, you risk running into an RNG which requires an integer array of a different size. There is no need to hardwire a value into your code, so don't.

What's wrong with my random number generator in Fortran 95 please?

This a randon number generator module that I use to compile along with my main program (not listed here)
When I try to compile my random number generator module to see if it works, I get the following message:
at line 61: call random_seed( put = seed)
Error: size of 'put' argument of 'random_seed' intrinsic too small <4/12>
What does it mean? How can I fix it?
module random_angle
contains
0
integer Function random_integer (N) ! return a random integer between 1 and N
integer, intent(in) :: N
real*8 :: x
call random_number(x)
random_integer = floor(real(N)*x)+1
end function random_integer
Real*8 Function gasdev() ! ch7.pg.280:gaussian distribution function using ran1 as random # generator
implicit none
! integer, intent(inout) :: idum
integer, save::iset
real*8:: fac,rsq,v1,v2
real*8, dimension(2) :: x
real*8, save :: gset
! if (idum.lt.0) iset=0
if (iset.eq.0) then
rsq = 0.0
do while (rsq > 1.0.or.rsq==0)
call random_number(x)
v1=2.*x(1)-1
v2=2.*x(2)-1
rsq=v1**2+v2**2
! print *, v1, v2,rsq
end do
fac=sqrt(-2.*log(rsq)/rsq)
gset=v1*fac
gasdev=v2*fac
iset=1
else
gasdev=gset
iset=0
endif
return
end Function gasdev
real*8 function NormalRandom (average, stddev)
implicit none
real*8, intent(in):: average, stddev
NormalRandom = average + stddev*gasdev()
end function NormalRandom
subroutine setSEED (seed)
implicit none
real*8:: x
integer, dimension(4), intent(inout):: seed
if (seed(1) == 0.0) &
seed = floor(1000*secnds(0.0)) +(/0, 37, 74, 111 /)
call random_seed( put=seed)
end subroutine setSEED
end module random_angle
When the compiler says
Error: size of 'put' argument of 'random_seed' intrinsic too small <4/12>
it means that the size of your variable seed is too small.
In this case you have seed of size 4 (and I guess the compiler must be expecting (at least) 12).
The size of the array must be of a certain size which depends on the compiler. You can determine, portably, the required size by a call to random_seed with another argument
integer seed_size
integer, allocatable :: seed(:)
call random_seed(size=seed_size)
allocate(seed(seed_size))
seed = ...
call random_seed(put=seed)
As Vladimir F points out in a comment, the gfortran document itself has an example of this approach.
If you don't care about portable, you could just use an array of size 12 with your choice of values.
As more advanced reading, I'll say another thing. The example I gave above really wasn't very comparable to your code. That is, you say that the input to the seed setting subroutine is guaranteed to be at least of size 4 and it may, or may not, contain values you want to use as seed.
As I noted above, you could change that to 12, but that isn't portable. If you want to be portable things get more awkward.
integer, dimension(4), intent(inout):: seed
has as dummy argument an explicit shape array of size 4. The actual argument in the main program is an array at least that size. However, this size is a specification expression and, alas, call random_seed(size=seed_size) doesn't give us something we can use in a specification expression.
Perhaps something like
subroutine setSEED (seed)
integer, allocatable, intent(inout) :: seed(:)
integer seed_size
! Determine the correct size for the seed
call random_seed(size=seed_size)
! If our seed isn't set, or is too small, kill it.
if (ALLOCATED(seed)) then
if (SIZE(seed)<seed_size.or.seed(LBOUND(seed,1))==0.) deallocate(seed)
end if
! If seed isn't allocated (perhaps we killed it because it was too small)
! then allocate it to the correct size and initialize it.
if (.not.ALLOCATED(seed)) then
allocate(seed(seed_size))
seed = ... ! Our fallback seed initialization
end if
! Finally, put the seed. Using one we set, or the one originally given.
call random_seed(put=seed)
end subroutine
This, of course, requires that the actual argument be allocatable, but if you're handling portable seed setting that's a good thing.

Fortran, 'dim' argument of 'size' intrinsic is not a valid dimension index

I'm new to Fortran.
For now, I'm trying to make a simple function that should print the coefficients of a matrix.
Originally I wanted to do something more interesting with the matrix (that's why I used the FUNCTION keyword), but I had to dumb it down, since "Hello world", and "multiply a number by 2" are the only programs I managed to compile so far.
Here is my code:
PROGRAM my_program
IMPLICIT NONE
INTEGER, EXTERNAL :: print_coefs
END PROGRAM my_program
FUNCTION print_coefs(arr)
IMPLICIT NONE
REAL, INTENT(IN), DIMENSION(:) :: arr
INTEGER :: print_coefs
INTEGER :: i,j
do i = 1, size(arr, 1)
do j = 1, size(arr, 2)
print *, arr(i,j)
enddo
enddo
print_coefs = 0
END FUNCTION
So I have this error at compile time:
Error: 'dim' argument of 'size' intrinsic at (1) is not a valid dimension index.
Why? Isn't size the right way to get the dimensions of the matrix?
Thanks for your help.
The array arr is declared as being of rank 1. So, assuming the compiler is pointing to the line where size(arr,2) is given, this is not valid code: it is asking for the size of the second (non-existent) dimension.
From the rest of the function print_coeffs it appears desirable that arr be declared as rank-2: real, intent(in), dimension(:,:) :: arr.
It should, however, be noted that a function like this (arr is an assumed-shape array) will require an explicit interface for the caller. That is, if you want to call this function eventually from the main program then integer, external :: print_coeffs isn't going to be sufficient. See other questions and answers on SO---such as here---for more details.

reading data from txt file in fortran

I am writing a FORTRAN program that reads data from a text file and writing it to the console. the data file looks something like this
1234567890123456 123456.789 987654.321 673647.890 654356.890
6172876534567890 768909.098 234543.890 654321.908 987890.090
I have the following lines of FORTRAN code that reads data and just writes them to the console
OPEN(1,FILE='data.txt')
READ(1,'(I16,3F9.3)') A ,B, C, D
WRITE (*, '(I16,3F9.3)') A,B,C,D
CLOSE(1)
Instead of getting displayed as the same values in the text file, the following is the output
1234567890123456*********89987.656 0.322
6172876534567890*********98234.547 0.891
Can you please help me with this.
Thanks much
List-directed IO (i.e., *) is easier, especially on input. Nevertheless, there are times to use full IO control so that is worth understanding. On input, the data items and descriptors must line up by column. For input, in Fw.d, the d doesn't matter if you have a decimal point in the data item. The fields must be wide enough on both input and output. There need to be enough descriptors, of types which match the variables and the data items. Compare to this example program:
program test_read
implicit none
integer, parameter :: VLI_K = selected_int_kind (18)
integer, parameter :: DR_K = selected_real_kind (14)
integer (VLI_K) :: i
real (DR_K) :: a, b, c, d
open (unit=15, file="data.txt", status='old', &
access='sequential', form='formatted', action='read' )
read (15, 110) i, a, b, c, d
110 format (I16, 4(1X, F10.0) )
write (*, 120) i, a, b, c, d
120 format ( I18, 4 (2X, F12.3) )
read (15, *) i, a, b, c, d
write (*, 120) i, a, b, c, d
end program test_read
I had the hardest time ever trying to use read, but finally...
If you want to read a matrix stored in a .txt file use this:
program FILEREADER
real, dimension(:,:), allocatable :: x
integer :: n,m
open (unit=99, file='array.txt', status='old', action='read')
read(99, *), n
read(99, *), m
allocate(x(n,m))
do I=1,n,1
read(99,*) x(I,:)
write(*,*) x(I,:)
enddo
end
And the "array.txt" file must be like this for instance (And placed in the same folder of the main):
4
3
0.0 1.0 2.0
3.0 4.0 5.0
6.0 7.0 8.0
9.0 10.0 11.0
Hope it works for everyone out there
Slight modification to the #Andrés Argüello Guillén answer.
Unlike most other solutions, my code does not force you to specify in advance the number of rows and columns.
CHARACTER(128) :: buffer
integer strlen, rows, cols
real, dimension(:,:), allocatable :: x
OPEN (1, file = 'matrix.txt', status='old', action='read')
!Count the number of columns
read(1,'(a)') buffer !read first line WITH SPACES INCLUDED
REWIND(1) !Get back to the file beginning
strlen = len(buffer) !Find the REAL length of a string read
do while (buffer(strlen:strlen) == ' ')
strlen = strlen - 1
enddo
cols=0 !Count the number of spaces in the first line
do i=0,strlen
if (buffer(i:i) == ' ') then
cols=cols+1
endif
enddo
cols = cols+1
!Count the number of rows
rows = 0 !Count the number of lines in a file
DO
READ(1,*,iostat=io)
IF (io/=0) EXIT
rows = rows + 1
END DO
REWIND(1)
print*, 'Number of rows:', rows
print*, 'Number of columns:', cols
allocate(x(rows,cols))
do I=1,rows,1
read(1,*) x(I,:)
write(*,*) x(I,:)
enddo
CLOSE (1)
matrix.txt
0.0 1.0 2.0
3.0 4.0 5.0
6.0 7.0 8.0
I used fixed format because the editing and inspecting of input files having fixed column structure is easier than that of zigzag data.
My problem was how the Fortran run-time reader procedures interpret the presence and absence of decimal dots. I am not sure that my solution was the best but I read the data lines as character arrays, split them to fields having length 12 characters then I read the fields by read(*) statements.
The reason is that you're specifying a width that is too small for the real numbers. Usually when the width doesn't fit, fortran will display asterisks, which happens in your case.
You have 9 digits, but you'll need at least 10, since the comma takes up a column as well.
So replacing 3F9.3 with 3F10.3 should do the trick.
It is usually better to read data in non fixed format. And to leave some leading spaces so that numbers can fit when writing them out.
integer(8) :: i
real(4) :: x, y, z
open(unit=1, file='data.txt')
read(1,*)i, x, y, z
write(*,'(i16, 3f11.3)')i, x, y, z
end

Resources