Tutorial 5
Tutorial 5
Sun Qinbo
Email:
[email protected]
Designing a Random Number Library
• Nondeterministic behavior turns out to be difficult to achieve
on a computer.
• Given that true nondeterminism is so difficultSince
to achieve in a
C++11, there is a
computer, libraries such as the random.h interface
<random>described
library in the C++
in this chapter must instead simulate randomness by carrying
standard. But here we are
implementing a simplified
out a deterministic process that satisfies the following
version using only <cstdlib>.
criteria:
1. The values generated by that process should be difficult
for human observers to predict.
2. Those values should appear to be random, in the sense
that they should pass statistical tests for randomness.
• Because the process is not truly random, the values generated
by the random.h interface are said to be pseudorandom.
Designing a Random Number Library
• The function rand from <cstdlib> takes no arguments and
returns an integer between 0 and RAND_MAX randomly. It is not
sufficient for the clients.
• Choosing the right set of functions
Selecting a random integer in a specified range
Choosing a random real number in a specified range
Simulating a random event with a specific probability
• The designers of the C++ library (and the earlier C libraries)
decided that rand should return the same random sequence
each time a program is run, so that it is possible to use rand
in a deterministic way in order to support debugging.
Set the initial value (seed) of the random number
generating process, e.g., the time when the program is run
The random.h Interface
/*
* File: random.h
* --------------
* This file exports functions for generating pseudorandom numbers.
*/
#ifndef _random_h
#define _random_h
/*
* Function: randomInteger
* Usage: int n = randomInteger(low, high);
* ----------------------------------------
* Returns a random integer in the range low to high, inclusive.
*/
#include <cstdlib>
#include <cmath>
#include <ctime>
#include "random.h"
using namespace std;
void initRandomSeed();
The random.cpp Implementation
/*
* Implementation
File: random.cppnotes: randomInteger
* -----------------------------------
----------------
* The
Thiscode
filefor
implements
randomInteger
the random.h
produces
interface.
the number in four steps:
*
*/
* 1. Generate a random real number d in the range [0 .. 1).
#include
* 2. Scale
<cstdlib>
the number to the range [0 .. N).
#include
* 3. Translate
<cmath>the number so that the range starts at low.
#include
* 4. Truncate
<ctime>
the result to the next lower integer.
#include
* "random.h"
using
* The namespace
implementation
std; is complicated by the fact that both the
* expression RAND_MAX + 1 and the expression high - low + 1 can
/** overflow
Private function
the integer
prototype
range. */
*/
static void initRandomSeed();
int randomInteger(int low, int high) {
initRandomSeed();
double d = rand() / (double(RAND_MAX) + 1);
double s = d * (double(high) - low);
return int(floor(low + s));
} Noted: The source code is
not correct.
The random.cpp Implementation
/*
* Implementation notes: randomInteger
randomReal
* -----------------------------------
--------------------------------
* The code for randomInteger
randomReal is produces
similar to
the
that
number
for in
randomInteger,
four steps:
* without the final conversion step.
*
*/1. Generate a random real number d in the range [0 .. 1).
* 2. Scale the number to the range [0 .. N).
double
* 3. Translate
randomReal(double
the numberlow,
so that
double
the
high)
range
{ starts at low.
* 4.
initRandomSeed();
Truncate the result to the next lower integer.
* double d = rand() / (double(RAND_MAX) + 1);
* The
double
implementation
s = d * (highis-complicated
low); by the fact that both the
* expression
return low RAND_MAX
+ s; + 1 and the expression high - low + 1 can
}* overflow the integer range.
*/
double
bool randomChance(double
randomReal(double low,
p) { double high) {
initRandomSeed();
double
return d
randomReal(0,
= rand() / (double(RAND_MAX)
1) < p; + 1);
} double s = d * (high - low);
return low + s;
}
bool randomBool() {
return randomChance(0.5);
}
The random.cpp Implementation
/*
* Implementation notes: setRandomSeed
randomChance
* -----------------------------------
----------------------------------
* The setRandomSeed
code for randomChance
function calls
simply
randomReal(0,
forwards its 1)
argument
and then
to checks
* srand.
whether The
the call
result
to is
initRandomSeed
less than theisrequested
required probability.
to set the
*
*/initialized flag.
*/
bool randomChance(double p) {
void initRandomSeed();
setRandomSeed(int seed) {
initRandomSeed();
return randomReal(0, 1) < p;
} srand(seed);
}
bool randomBool() {
return randomChance(0.5);
}
The random.cpp Implementation
/*
* Implementation notes: setRandomSeed
initRandomSeed
* -----------------------------------
------------------------------------
* The setRandomSeed
initRandomSeedfunctionfunctionsimply declares forwards
a static itsvariable
argumentthat
to
* srand.
keeps track
The callof whether
to initRandomSeed
the seed hasis beenrequired
initialized.
to set the
The
* initialized
first time initRandomSeed
flag. is called, initialized is false,
*/
* so the seed is set to the current time.
*/
void setRandomSeed(int seed) {
voidinitRandomSeed();
initRandomSeed() {
srand(seed);
static bool initialized = false;
} if (!initialized) {
srand(int(time(NULL)));
initialized = true;
}
The lifetime of static variables begins the first time the program flow
} encounters the declaration and it ends at program termination. The
compiler allocates only one copy of initialized, which is initialized
exactly once, and then shared by all calls to initRandomSeed. This
ensures that the initialization step must be performed once and only once.