Correctly setting random seeds for repeatability - fortran

The method for setting random seeds using the Fortran 90 subroutine random_seed is quite straightforward.
call random_seed( put=seed )
But I can't find any information about guidelines for setting the seed (which is absolutely necessary when you want repeatability). Folklore I've heard in the past suggested that scalar seeds should be large. E.g. 123456789 is a better seed than 123. The only support for this I can find on the web is that it is suggested for the ifort extension function ran() that one use a "large, odd integer value"
I understand this might be implementation specific and am using gfortran 4.8.5 but am also interested in ifort and (if possible) general guidelines that are independent of implementation. Here's some example code:
# for compactness, assume seed size of 4, but it will depend on
# the implementation (e.g. for my version of gfortran 4.8.5 it is 12)
seed1(1:4) = [ 123456789, 987654321, 456789123, 7891234567 ]
seed2(1:4) = 123456789
seed3(1:4) = [ 1, 2, 3, 4 ]
I'd guess that seed1 is fine, but pretty verbose if you're setting it manually (as I am) as seed length can be 12 or 33 or whatever. And I'm not even sure that it's fine because I haven't been able to find any guidelines at all about setting these seeds. I.e. these seeds should be negative for all I know, or 3 digit even numbers, etc. although I guess you'd hope the implementation would warn you about that (?).
seed2 and seed3 are obviously more convenient to set and for all I know are just as good. #Ross suggests that seed2 is in fact fine in his answer here: Random number generator (RNG/PRNG) that returns updated value of seed
So my question in summary is just: How can I correctly set the seed? Are any or all of seed1 to seed3 acceptable?

Guidelines for setting the seed depend on the PRNG algorithm that RANDOM_NUMBER uses, but in general the more "entropy" you provide the better.
If you have a single scalar value, you can use some simple PRNG to expand that to the full seed array required by RANDOM_SEED. See e.g. the function lcg in the example code at https://gcc.gnu.org/onlinedocs/gcc-4.9.1/gfortran/RANDOM_005fSEED.html
Current versions of GFortran have some protections against bad seeds, and it should be relatively immune towards "dumb" seeding (e.g. all values of seed(:) identical, or all values small or even zero), but for portability to other compilers following something like I suggested above might still be a good idea.

What you provide to random_seed( put=... ) is used to determine the starting state of the generator, which (as janneb states) should have as much entropy as reasonably possible. You could construct some relatively sophisticated method of generating this entropy - grabbing from the system somehow is a good choice for this. The code janneb links is a good example.
However, I typically like to be able to reproduce a single run from a given seed if necessary. This is useful for debugging and regression testing. Then, for production runs, the code can pull a single seed 'randomly' somehow. Therefore, I want to get good RNG from a single 'seed'. In my experience, this is easily achieved by providing this single seed then letting the generator add entropy by generating numbers. Consider the following example:
program main
implicit none
integer, parameter :: wp = selected_real_kind(15,307)
integer, parameter :: n_discard = 100
integer :: state_size, i
integer, allocatable, dimension(:) :: state
real(wp) :: ran, oldran
call random_seed( size=state_size )
write(*,*) '-- state size is: ', state_size
allocate(state(state_size))
! -- Simple method of initializing seed from single scalar
state = 20180815
call random_seed( put=state )
! -- 'Prime' the generator by pulling the first few numbers
! -- In reality, these would be discarded but I will print them for demonstration
ran = 0.5_wp
do i=1,n_discard
oldran = ran
call random_number(ran)
write(*,'(a,i3,2es26.18)') 'iter, ran, diff: ', i, ran, ran-oldran
enddo
! Now the RNG is 'ready'
end program main
Here, I give a single seed, and then generate a random number 100 times. Typically, I would discard these initial, potentially corrupted, numbers. In this example, I'm printing them to see whether they look non-random. Running with PGI 15.10:
enet-mach5% pgfortran --version
pgfortran 15.10-0 64-bit target on x86-64 Linux -tp sandybridge
The Portland Group - PGI Compilers and Tools
Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
enet-mach5% pgfortran main.f90 && ./a.out
-- state size is: 34
iter, ran, diff: 1 8.114813341476008191E-01 3.114813341476008191E-01
iter, ran, diff: 2 8.114813341476008191E-01 0.000000000000000000E+00
iter, ran, diff: 3 8.114813341476008191E-01 0.000000000000000000E+00
iter, ran, diff: 4 8.114813341476008191E-01 0.000000000000000000E+00
iter, ran, diff: 5 8.114813341476008191E-01 0.000000000000000000E+00
iter, ran, diff: 6 2.172220012214012286E-01 -5.942593329261995905E-01
iter, ran, diff: 7 2.172220012214012286E-01 0.000000000000000000E+00
iter, ran, diff: 8 2.172220012214012286E-01 0.000000000000000000E+00
iter, ran, diff: 9 2.172220012214012286E-01 0.000000000000000000E+00
iter, ran, diff: 10 2.172220012214012286E-01 0.000000000000000000E+00
iter, ran, diff: 11 6.229626682952016381E-01 4.057406670738004095E-01
iter, ran, diff: 12 6.229626682952016381E-01 0.000000000000000000E+00
iter, ran, diff: 13 6.229626682952016381E-01 0.000000000000000000E+00
iter, ran, diff: 14 6.229626682952016381E-01 0.000000000000000000E+00
iter, ran, diff: 15 6.229626682952016381E-01 0.000000000000000000E+00
iter, ran, diff: 16 2.870333536900204763E-02 -5.942593329261995905E-01
iter, ran, diff: 17 2.870333536900204763E-02 0.000000000000000000E+00
iter, ran, diff: 18 4.344440024428024572E-01 4.057406670738004095E-01
iter, ran, diff: 19 4.344440024428024572E-01 0.000000000000000000E+00
iter, ran, diff: 20 4.344440024428024572E-01 0.000000000000000000E+00
iter, ran, diff: 21 8.401846695166028667E-01 4.057406670738004095E-01
iter, ran, diff: 22 8.401846695166028667E-01 0.000000000000000000E+00
iter, ran, diff: 23 6.516660036642036857E-01 -1.885186658523991809E-01
iter, ran, diff: 24 6.516660036642036857E-01 0.000000000000000000E+00
iter, ran, diff: 25 6.516660036642036857E-01 0.000000000000000000E+00
iter, ran, diff: 26 5.740667073800409526E-02 -5.942593329261995905E-01
iter, ran, diff: 27 5.740667073800409526E-02 0.000000000000000000E+00
iter, ran, diff: 28 2.746286719594053238E-01 2.172220012214012286E-01
iter, ran, diff: 29 2.746286719594053238E-01 0.000000000000000000E+00
iter, ran, diff: 30 2.746286719594053238E-01 0.000000000000000000E+00
iter, ran, diff: 31 6.803693390332057334E-01 4.057406670738004095E-01
iter, ran, diff: 32 6.803693390332057334E-01 0.000000000000000000E+00
iter, ran, diff: 33 3.033320073284073715E-01 -3.770373317047983619E-01
iter, ran, diff: 34 3.033320073284073715E-01 0.000000000000000000E+00
iter, ran, diff: 35 7.090726744022077810E-01 4.057406670738004095E-01
iter, ran, diff: 36 1.148133414760081905E-01 -5.942593329261995905E-01
iter, ran, diff: 37 1.148133414760081905E-01 0.000000000000000000E+00
iter, ran, diff: 38 1.435166768450102381E-01 2.870333536900204763E-02
iter, ran, diff: 39 1.435166768450102381E-01 0.000000000000000000E+00
iter, ran, diff: 40 3.607386780664114667E-01 2.172220012214012286E-01
iter, ran, diff: 41 7.664793451402118762E-01 4.057406670738004095E-01
iter, ran, diff: 42 7.664793451402118762E-01 0.000000000000000000E+00
iter, ran, diff: 43 2.009233475830143334E-01 -5.655559975571975428E-01
iter, ran, diff: 44 2.009233475830143334E-01 0.000000000000000000E+00
iter, ran, diff: 45 6.353673500258167905E-01 4.344440024428024572E-01
iter, ran, diff: 46 4.110801709961720007E-02 -5.942593329261995905E-01
iter, ran, diff: 47 4.110801709961720007E-02 0.000000000000000000E+00
iter, ran, diff: 48 8.812926866162200668E-01 8.401846695166028667E-01
iter, ran, diff: 49 8.812926866162200668E-01 0.000000000000000000E+00
iter, ran, diff: 50 9.386993573542241620E-01 5.740667073800409526E-02
iter, ran, diff: 51 3.444400244280245715E-01 -5.942593329261995905E-01
iter, ran, diff: 52 7.501806915018249811E-01 4.057406670738004095E-01
iter, ran, diff: 53 9.961060280922282573E-01 2.459253365904032762E-01
iter, ran, diff: 54 9.961060280922282573E-01 0.000000000000000000E+00
iter, ran, diff: 55 8.221603419923440015E-02 -9.138899938929938571E-01
iter, ran, diff: 56 4.879567012730348097E-01 4.057406670738004095E-01
iter, ran, diff: 57 1.109193695682364478E-01 -3.770373317047983619E-01
iter, ran, diff: 58 7.625853732324401335E-01 6.516660036642036857E-01
iter, ran, diff: 59 7.625853732324401335E-01 0.000000000000000000E+00
iter, ran, diff: 60 2.831393817822487335E-01 -4.794459914501914000E-01
iter, ran, diff: 61 6.888800488560491431E-01 4.057406670738004095E-01
iter, ran, diff: 62 7.462867195940532383E-01 5.740667073800409526E-02
iter, ran, diff: 63 8.036933903320573336E-01 5.740667073800409526E-02
iter, ran, diff: 64 8.036933903320573336E-01 0.000000000000000000E+00
iter, ran, diff: 65 1.644320683984688003E-01 -6.392613219335885333E-01
iter, ran, diff: 66 5.701727354722692098E-01 4.057406670738004095E-01
iter, ran, diff: 67 6.849860769482774003E-01 1.148133414760081905E-01
iter, ran, diff: 68 1.481334147600819051E-01 -5.368526621881954952E-01
iter, ran, diff: 69 5.538740818338823146E-01 4.057406670738004095E-01
iter, ran, diff: 70 1.605380964906970576E-01 -3.933359853431852571E-01
iter, ran, diff: 71 5.662787635644974671E-01 4.057406670738004095E-01
iter, ran, diff: 72 7.672021111475118005E-01 2.009233475830143334E-01
iter, ran, diff: 73 6.360901160331167148E-01 -1.311119951143950857E-01
iter, ran, diff: 74 6.647934514021187624E-01 2.870333536900204763E-02
iter, ran, diff: 75 9.231234697231371911E-01 2.583300183210184287E-01
iter, ran, diff: 76 3.288641367969376006E-01 -5.942593329261995905E-01
iter, ran, diff: 77 5.034149292976053403E-02 -2.785226438671770666E-01
iter, ran, diff: 78 3.249701648891658579E-01 2.746286719594053238E-01
iter, ran, diff: 79 4.110801709961720007E-01 8.611000610700614288E-02
iter, ran, diff: 80 7.268168600551945246E-01 3.157366890590225239E-01
iter, ran, diff: 81 1.325575271289949342E-01 -5.942593329261995905E-01
iter, ran, diff: 82 2.147735613282293343E-01 8.221603419923440015E-02
iter, ran, diff: 83 8.951429003614350677E-01 6.803693390332057334E-01
iter, ran, diff: 84 9.606624794444940107E-02 -7.990766524169856666E-01
iter, ran, diff: 85 8.749502748152764298E-01 7.788840268708270287E-01
iter, ran, diff: 86 6.864316089628772488E-01 -1.885186658523991809E-01
iter, ran, diff: 87 3.753116578189263919E-01 -3.111199511439508569E-01
iter, ran, diff: 88 4.614216639259325348E-01 8.611000610700614288E-02
iter, ran, diff: 89 8.632683590919612016E-01 4.018466951660286668E-01
iter, ran, diff: 90 5.110403908483931446E-01 -3.522279682435680570E-01
iter, ran, diff: 91 3.512250603649960112E-01 -1.598153304833971333E-01
iter, ran, diff: 92 2.984351275420635830E-01 -5.278993282293242828E-02
iter, ran, diff: 93 7.902858007228701354E-01 4.918506731808065524E-01
iter, ran, diff: 94 9.136098520217217356E-01 1.233240512988516002E-01
iter, ran, diff: 95 8.360105557375590024E-01 -7.759929628416273317E-02
iter, ran, diff: 96 7.623052313611680120E-01 -7.370532437639099044E-02
iter, ran, diff: 97 2.525198759725810760E-02 -7.370532437639099044E-01
iter, ran, diff: 98 9.228433278518650695E-01 8.975913402546069619E-01
iter, ran, diff: 99 1.283834133499510699E-01 -7.944599145019139996E-01
iter, ran, diff: 100 7.311534560989940701E-01 6.027700427490430002E-01
8 of the first 10 numbers generated are the repeated! This is a good illustration of why some generators require a high-entropy state in the first place. However, after 'some' time, the numbers start to look reasonable.
For my applications, 100 or so random numbers is a very small cost, so whenever I seed a generator, I prime them in this manner. I didn't observe this obviously bad behavior on ifort 16.0, gfortran 4.8, or gfortran 8.1. Non-repeating numbers is a pretty low bar, though. So I would prime for all compilers, not just ones I have observed bad behavior for.
From the comments, some compilers attempt to eliminate bad behavior by processing the input state in some way to yield the actual internal state. Gfortran uses an "xor cipher". The operation is reversed on a get.

Related

How to print table of 12 using recursion, I want it upto 10 but on running it turns out to be upto 12

I was trying to create a program to print table of 12 using recursion as I wrote a simple program for this I did get table, but table was instead upto 144 (12times12=144) instead of 120(12times10=120) I am sharing my code and output with you guys I was writing code in C++
//we will print table of 12 using concept of recursion
//a table of 12 is like this
//12 24 36 48 60 72 84 96 108 120
#include<iostream>
using namespace std;
void table(int n)
{
if(n==1)
{
cout<<12<<"\n";
return;
}
table(n-1);
cout<<n*12<<"\n";
}
int main(void)
{
table(12);
}
and now here is out put of this program
12
24
36
48
60
72
84
96
108
120
132
144
please help me what I'm missing here I am positive that adding some condition will help I tried one adding if(n==12) { return;} but it prevents does nothing as in the end it is return n*12

Error related to EOF command in fortran code

I am a beginner to Fortran and am trying to compile a Fixed-Term Fortran Code using gfortran. I got a bunch of errors, which I could fix them. However, there is an Error related to "EOF" which I could not solve it. Is there any way to fix this problem? (The two "EOF" lines are lines 40 and 121.)
37 OPEN(4,FILE="ABCE.Pn")
38
39 OPEN(5,FILE="../sta.txt")
40 DO WHILE (.not.EOF(5))
41 N=N+1
42 READ(5,*)STA(N)%COD,STA(N)%NAME,STA(N)%LAT,
43 $ STA(N)%LON,STA(N)%H
44 ENDDO
45 NSTA=N
46 CLOSE(5)`
......
121 DO WHILE (.not.EOF(1))
122 READ(1,'(A60)',ERR=999) TIT
123 C IF(IYEAR.GE.2008.OR.
(IYEAR.EQ.2007.AND.MONTH.GE.11))
124 C $ TIT=TIT(2:60)
125 IF(TIT(1:60).EQ.'')THEN ! NEW EARTHQUAKE`
The error:
DO WHILE (.not.EOF(5))
1
Error: Operand of .not. operator at (1) is REAL(4)
ReadP2Pn.for:121.21:
DO WHILE (.not.EOF(1))
1
Error: Operand of .not. operator at (1) is REAL(4)
EOF(5) is non-standard. You should check for EOF in the read statement (which sadly looks like a goto) :
40 DO WHILE (.true.)
41 N=N+1
42 READ(5,*,end=990)STA(N)%COD,STA(N)%NAME,STA(N)%LAT,
43 $ STA(N)%LON,STA(N)%H
44 ENDDO
45 990 NSTA=N

How to find different set of two vectors with no repetitions?

I am writing the code to return the data in v1 that is not in v2 vector, with no repetitions using C++.
std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
std::inserter(diff, diff.begin()));
However, when my input v1,v2 are
v1=[137 138 139 140 141 142 143 144 148 150 157 158 161]
v2=[138 157 150 140 137 158 141 139 143 148]
The output results in unexpected solution as
diff=[ 137 139 140 141 142 143 144 148 150 161]
While, my expected solution must be
diff=[ 142 144 161]
What should I correct my function? Thanks
v2 needs to be sorted. As does v1 (which it is). The function set_difference assumes both vectors are sorted.
The algorithm only has to walk each vector once, and only needs to compare the current cursor of each vector. This is a significant performance improvement, and space saving from an algorithm which worked with arbitrary inputs.
std::set_difference:
Copies the elements from the sorted range [first1, last1) which are
not found in the sorted range [first2, last2) to the range beginning
at d_first
http://en.cppreference.com/w/cpp/algorithm/set_difference
You must sort your vectors, before difference them
Look at the method:
std::set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(),
std::inserter(diff, diff.begin()));
It's called set_difference for a reason :)
Just use set containers instead of your vector ones. They will make sure that your data is sorted and that the algorithm is successful.

MPI partition and gather 2D array in Fortran

I have a 2D array where I'm running some computation on each process. Afterwards, I need to gather all the computed columns back to the root processes. I'm currently partitioning in a first come first serve manner. In pseudo code, the main loop looks like:
DO i = mpi_rank + 1, num_columns, mpi_size
array(:,i) = do work here
After this is completed, I need to gather these columns into the correct indices back in the root process. What is the best way to do this? It looks like MPI_GATHERV could do what I want if the partitioning scheme was different. However, I'm not sure what the best way to partition that would be since num_columns and mpi_size are not necessarily evenly divisible.
I suggest the following approach:
Cut the 2D array into chunks of "almost equal" size, i.e. with local number of columns close to num_columns / mpi_size.
Gather chunks with mpi_gatherv, which operates with chunks of different size.
To get "almost equal" number of columns, set local number of columns to integer value of num_columns / mpi_size and increment by one only for first mod(num_columns,mpi_size) mpi tasks.
The following table demonstrates the partitioning of (10,12) matrix on 5 MPI processes:
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
01 02 03 11 12 13 21 22 31 32 41 42
Here the first digit is an id of the process, the second digit is a number of local columns.
As you can see, processes 0 and 1 got 3 columns each, while all other processes got only 2 columns each.
Below you can find working example code that I wrote.
The trickiest part would be the generation of rcounts and displs arrays for MPI_Gatherv. The discussed table is an output of the code.
program mpi2d
implicit none
include 'mpif.h'
integer myid, nprocs, ierr
integer,parameter:: m = 10 ! global number of rows
integer,parameter:: n = 12 ! global number of columns
integer nloc ! local number of columns
integer array(m,n) ! global m-by-n, i.e. m rows and n columns
integer,allocatable:: loc(:,:) ! local piece of global 2d array
integer,allocatable:: rcounts(:) ! array of nloc's (for mpi_gatrherv)
integer,allocatable:: displs(:) ! array of displacements (for mpi_gatherv)
integer i,j
! Initialize
call mpi_init(ierr)
call mpi_comm_rank(MPI_COMM_WORLD, myid, ierr)
call mpi_comm_size(MPI_COMM_WORLD, nprocs, ierr)
! Partition, i.e. get local number of columns
nloc = n / nprocs
if (mod(n,nprocs)>myid) nloc = nloc + 1
! Compute partitioned array
allocate(loc(m,nloc))
do j=1,nloc
loc(:,j) = myid*10 + j
enddo
! Build arrays for mpi_gatherv:
! rcounts containes all nloc's
! displs containes displacements of partitions in terms of columns
allocate(rcounts(nprocs),displs(nprocs))
displs(1) = 0
do j=1,nprocs
rcounts(j) = n / nprocs
if(mod(n,nprocs).gt.(j-1)) rcounts(j)=rcounts(j)+1
if((j-1).ne.0)displs(j) = displs(j-1) + rcounts(j-1)
enddo
! Convert from number of columns to number of integers
nloc = m * nloc
rcounts = m * rcounts
displs = m * displs
! Gather array on root
call mpi_gatherv(loc,nloc,MPI_INT,array,
& rcounts,displs,MPI_INT,0,MPI_COMM_WORLD,ierr)
! Print array on root
if(myid==0)then
do i=1,m
do j=1,n
write(*,'(I04.2)',advance='no') array(i,j)
enddo
write(*,*)
enddo
endif
! Finish
call mpi_finalize(ierr)
end
What about gathering in chunks of size mpi_size?
To shorten this here, I'll assume that num_columns is a multiple of mpi_size. In your case the gathering should look something like (lda is the first dimension of array):
DO i = 1, num_columns/mpi_size
IF (rank == 0) THEN
CALL MPI_GATHER(MPI_IN_PLACE, lda, [TYPE], array(1,(i-1)*mpi_size+1), lda, [TYPE], 0, MPI_COMM_WORLD, ierr)
ELSE
CALL MPI_GATHER(array(1, rank + (i-1)*mpi_size + 1), lda, [TYPE], array(1,(i-1)*mpi_size+1), lda, [TYPE], 0, MPI_COMM_WORLD, ierr)
END IF
ENDDO
I'm not so sure with the indices and if this actually works, but I think, you should get the point.

I can't figure out what is wrong with this randomizer

I'm new to C++. Only been programming for 2 days so this will probably look messy. The purpose of the program is that you enter a word, and then the program randomizes the placement of the letters in the word.
I have three questions.
Why, if the same string is entered twice, will the same "random" numbers be output?
How can I make sure no random number is picked twice. I already tried an IF statement nested inside the FOR statement but it just made things worse.
What will make this work?
The code:
#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <stdio.h>
#include <string.h>
using namespace std;
int main () {
cout << "Enter word to be randomized: ";
char rstring[30];
char rstring2[30];
cin >> rstring;
strcpy(rstring2, rstring);
int length;
length = strlen(rstring);
int max=length;
int min=0;
int randint;
for (int rdm=0; rdm<length; rdm++) {
randint=rand()%(max-min)+min;
cout << rstring[rdm]; //This is temporary. Just a visualization of what I'm doing.
cout << randint << endl; //Temporary as well.
rstring2[randint]=rstring[rdm];
}
cout << endl << rstring2 << endl;
return 0;
}
If you compile and run this you will notice that the same random numbers are output for the same text. Like "hello" outputs 24330. Why is this random generator generating nonrandom numbers?
You need to seed your random number generator to get different results with each run. Otherwise, (as you have noticed) you will get the same random numbers with each run.
Put this at the start of the program:
srand(time(NULL));
This will seed the random number generator with time - which will likely be different between runs.
Note that you'll also need #include <time.h> to access the time() function.
You're not using a random number generator. You're calling rand(), a pseudo-random number generator, which produces sequences of numbers that share many properties with truly random numbers (e.g. mean, standard deviation, frequency spectrum will all be correct).
To get a different sequence, you have to initialize the seed using srand(). The usual way to do this is:
srand(time(NULL));
Furthermore, a sequence that guarantees the same number cannot be picked twice, is no longer a sequence of i.i.d. (independent identically distributed) random numbers. (the sequence is highly dependent) Most uses of random numbers rely on the i.i.d. property, so the library-provided functions are i.i.d. However, filtering out repeats yourself is not especially hard.
If you don't want to change the cardinality (number of occurrences) of each character in the string, the easiest thing to do is not pick one character after the other, but randomly pick a pair to swap. By only swapping, you change order but not cardinality.
You always get the same random numbers because you don't seed this random number generator. Call srand() before your first call to rand(). Examples: http://www.cplusplus.com/reference/clibrary/cstdlib/srand/
The random number generated by rand() is pseudo-random. C++ rand() documentation says following
rand() Returns a pseudo-random integral number in the range 0 to RAND_MAX.
This number is generated by an algorithm that returns a sequence of apparently non-related numbers each time it is called. This algorithm uses a seed to generate the series, which should be initialized to some distinctive value using srand.
Because (at least on Linux) pseudo-random number generators are seeded with the same value (to make programs more deterministic, so two consecutive identical runs will give the same answers).
You could seed your PRNG with a different value (the time, the pid, whatever). On Linux you could also consider reading the /dev/urandom (or much rarely, even the /dev/random) pseudo file - often to seed your PRNG.
The code below remembers what random number that was previously picked.
It generates a unique random number only once.
It stores results in an array, so that when rand() produces a number
that already exists, it does not store that number in the array.
#include <ctime>
#include <iostream>
using namespace std;
int main()
{
int size=100;
int random_once[100];
srand(time(0));
cout<<"generating unique random numbers between [0 and "<<size <<"] only once \n\n";
for (int i=0;i<size;i++) // generate random numbers
{
random_once[i]=rand() % size;
//if number already exists, dont store that number in the array
for(int j=0;j<i;j++) if (random_once[j]==random_once[i]) i--;
}
for ( i=0;i<size;i++) cout<<" "<<random_once[i]<<"\t";
cout<<"\n";
return 0;
}
Output :
generating unique random numbers between [0 and 100] only once
50 80 99 16 11 56 48 36 21 34
90 87 33 85 96 77 63 5 60 52
59 4 84 30 7 95 25 1 45 49
10 43 44 82 22 74 32 68 70 86
57 24 39 51 83 2 81 71 42 94
78 72 41 73 92 35 76 9 3 58
19 40 37 67 31 23 55 69 8 17
64 46 93 27 28 91 26 65 47 14
15 75 79 88 62 97 54 12 18 89
13 38 61 0 29 66 53 6 98 20
Press any key to continue