Generating random numbers

Problem

You want to generate random numbers.

Solution

For uniformly distributed (flat) random numbers, use runif(). By default, its range is from 0 to 1.

runif(1)
# 0.5581546
 
# Get a vector of 4 numbers
runif(4)
# 0.383330465 0.005814167 0.879704937 0.873534007
 
# Get a vector of 3 numbers from 0 to 100
runif(3, min=0, max=100)
# 78.09879 85.37001 15.13357
 
# Get 3 integers from 0 to 100
# Use max=101 because it will never actually equal 101
floor(runif(3, min=0, max=101))
# 40 59 64
# This will do the same thing
sample(1:100, 3, replace=T)
 
# To generate integers WITHOUT replacement:
sample(1:100, 3, replace=F)

To generate numbers from a normal distribution, use rnorm(). By default the mean is 0 and the standard deviation is 1.

rnorm(4)
#  1.04043144 -1.02006411  1.97268110  0.02424849
 
# Use a different mean and standard deviation
rnorm(4, mean=50, sd=10)
# 30.29251 48.75306 51.08491 50.04595
 
# To check that the distribution looks right, make a histogram of the numbers
x <- rnorm(400, mean=50, sd=10)
hist(x)

 

 

Generating repeatable sequences of random numbers

Problem

You want to generate a sequence of random numbers, and then generate that same sequence again later.

Solution

Use set.seed(), and pass in a number as the seed.

set.seed(423)
runif(3)
# 0.1089715 0.5973455 0.9726307
 
set.seed(423)
runif(3)
# 0.1089715 0.5973455 0.9726307

 

 

Saving the state of the random number generator

Table of contents

Problem

You want to save and restore the state of the random number generator

Solution

Save .Random.seed to another variable.

# For this example, set the random seed
set.seed(423)
runif(3)
# 0.1089715 0.5973455 0.9726307
 
# Save the seed
oldseed <- .Random.seed
 
runif(3)
# 0.7973768 0.2278427 0.5189830
 
# Do some other stuff with RNG here, such as:
# runif(30)
# ...
 
# Restore the seed
.Random.seed <- oldseed
 
# Get the same random numbers as before, after saving the seed
runif(3)
# 0.7973768 0.2278427 0.5189830

If no random number generator has been used in your R session, the variable .Random.seed will not exist. If you cannot be certain that an RNG has been used before attempting to save, the seed, you should check for it before saving and restoring:

oldseed <- NULL
if (exists(".Random.seed"))  oldseed <- .Random.seed
 
# Do some other stuff with RNG here, such as:
# runif(30)
# ...
 
if (!is.null(oldseed))
    .Random.seed <- oldseed

Saving and restoring the state of the RNG in functions

If you attempt to restore the state of the random number generator within a function by using .Random.seed <- x, it will not work, because this operation changes a local variable named .Random.seed, instead of the variable in the global envrionment.

Here are two examples. What these functions are supposed to do is generate some random numbers, while leaving the state of the RNG unchanged.

# This is the bad version
bad_rand_restore <- function() {
    if (exists(".Random.seed"))  oldseed <- .Random.seed
    print(runif(3))
    if (exists(".Random.seed"))  .Random.seed <- oldseed
}
 
# This is the good version
rand_restore <- function() {
    if (exists(".Random.seed"))  oldseed <- get(".Random.seed", .GlobalEnv)
    print(runif(3))
    if (exists(".Random.seed"))  assign(".Random.seed", oldseed, .GlobalEnv)
}
 
# The bad version changes the RNG state, so random numbers keep changing
set.seed(423)
bad_rand_restore()
# 0.1089715 0.5973455 0.9726307
bad_rand_restore()
# 0.7973768 0.2278427 0.5189830
bad_rand_restore()
# 0.6929255 0.8104453 0.1019465
 
# The good version doesn't alter the RNG state, so random numbers stay the same
set.seed(423)
rand_restore()
# 0.1089715 0.5973455 0.9726307
rand_restore()
# 0.1089715 0.5973455 0.9726307
rand_restore()
# 0.1089715 0.5973455 0.9726307

Notes

.Random.seed should not be modified by the user.

 

Rounding numbers

Problem

You want to round numbers.

Solution

A short description of the solution.

x <- seq(-2.5, 2.5, by=.5)
# -2.5 -2.0 -1.5 -1.0 -0.5  0.0  0.5  1.0  1.5  2.0  2.5
 
# Round to nearest, with .5 values rounded to even number.
round(x)
# -2   -2   -2   -1    0    0    0    1    2    2    2
 
# Round up
ceiling(x)
# -2   -2   -1   -1    0    0    1    1    2    2    3
 
# Round down
floor(x)
# -3   -2   -2   -1   -1    0    0    1    1    2    2
 
# Round toward zero
trunc(x)
# -2   -2   -1   -1    0    0    0    1    1    2    2

It is also possible to round to other values besides one:

x <- c(.001, .07, 1.2, 44.02, 738, 9927) 
# 0.001    0.070    1.200   44.020  738.000 9927.000
 
# Round to one decimal place
round(x, digits=1)
# 0.0      0.1      1.2     44.0    738.0   9927.0
 
# Round to tens place
round(x, digits=-1)
# 0        0        0       40      740     9930
 
# Round to nearest 5
round(x/5)*5
# 0        0        0       45      740     9925
 
# Round to nearest .02
round(x/.02)*.02
# 0.00     0.08     1.20    44.02   738.00  9927.00

 

Comparing floating point numbers

Problem

Comparing floating point numbers does not always work as you expect. For example:

0.3 == 3*.1
# FALSE
 
(0.1 + 0.1 + 0.1) - 0.3
# 5.551115e-17
 
x <- seq(0, 1, by=.1)
# 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
10*x - round(10*x)
# [1] 0.000000e+00 0.000000e+00 0.000000e+00 4.440892e-16 0.000000e+00
# [6] 0.000000e+00 8.881784e-16 8.881784e-16 0.000000e+00 0.000000e+00
#[11] 0.000000e+00

Solution

There is no universal solution, because this issue is inherent to the storage format for non-integer (floating point) numbers, in R and computers in general.