aboutsummaryrefslogtreecommitdiff
path: root/R/SyncRNG.R
blob: 72156df827aa8a122ea980660befda6d988a8028 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
library(methods)

#' A Reference Class for SyncRNG
#'
#' @field seed The seed for the random number generator
#' @field state The current state of the RNG, should not be modified by the 
#' user
#'
#' @examples
#' s <- SyncRNG(seed=123456)
#' for (i in 1:10)
#'   cat(s$randi(), '\n')
#'
SyncRNG <- setRefClass('SyncRNG',
	fields=list(
		    seed='numeric',
		    state='numeric'
		    ),
	methods=list(
		initialize=function(..., seed=0) {
			"Initialize the RNG using the C function R_syncrng_seed"
			seed <<- seed
			tmp <- .Call('R_syncrng_seed',
			     as.numeric(seed))
			state <<- tmp[1:4]
			callSuper(...)
		},
		randi=function() {
			"Generate a single random 32-bit integer"
			tmp <- .Call('R_syncrng_rand',
				     as.numeric(state))
			state <<- tmp[1:4]
			return(tmp[5])
		},
		rand=function() {
			"Generate a single random float in the range [0, 1)"
			r <- randi()
			return (r * 2.3283064365387e-10)
		},
		randbelow=function(n) {
			"Generate a random integer below a given number"
			maxsize <- 2^32
			if (n >= maxsize) {
				warning(paste("Underlying random generator ",
					     "does not supply\n enough bits ",
					     "to choose from a population ",
					     "range this large.\n"))
				return(round(rand() * n))
			}
			rem <- maxsize %% n
			limit <- (maxsize - rem) / maxsize
			r <- rand()
			while (r >= limit)
				r <- rand()
			return(round(r*maxsize) %% n)
		},
		shuffle=function(x) {
			"Randomly shuffle a provided array of values"
			y <- x
			for (i in rev(1:(length(y)-1))) {
				j <- randbelow(i+1)
				tmp <- y[i+1]
				y[i+1] <- y[j+1]
				y[j+1] <- tmp
			}
			return(y)
		}
		)
	)