Class: Xoroshiro::Random
- Inherits:
-
Object
- Object
- Xoroshiro::Random
- Defined in:
- lib/xoroshiro.rb,
ext/xoroshiro/xoroshiro.c
Overview
Provides pseudo-random variate generation based on Xoroshiro256**.
Quoting the original Xoroshiro creators:
…xoshiro256** 1.0 [is] one of our all-purpose, rock-solid generators. It has excellent (sub-ns) speed, a state (256 bits) that is large enough for any parallel application, and it passes all tests we are aware of.
This generator outperforms MT19937, the underlying engine for Kernel::rand
, in both speed and statistical performance.
Instance Method Summary collapse
-
#each ⇒ Object
Yields random values determined by the range argument of
initialize
. -
#get_state ⇒ Object
Retrieve the current 256 bit state of the generator.
-
#initialize(range = nil, seed: nil) ⇒ Random
constructor
- Arguments
-
@param range [
nil
,Range
,Numeric
] specify the range and type of the values produced by:each
.
-
#jump ⇒ Object
Update the state to the equivalent of 2^128 calls to rand().
-
#long_jump ⇒ Object
Update the state to the equivalent of 2^192 calls to rand().
-
#rand(*args) ⇒ Object
Generate a random value as specified by
args
. -
#set_state(seeds) ⇒ Object
Explicitly set the 256 bit state of the generator.
Constructor Details
#initialize(range = nil, seed: nil) ⇒ Random
- Arguments
-
@param range [
nil
,Range
,Numeric
] specify the range and type of the values produced by:each
. (default:nil
)-
nil
-> generate Uniform(0,1)Float
values -
Range
-> generate uniformly distributed values within the range of type:-
if both bounds are
Integer
->Integer
-
otherwise ->
Float
-
-
Numeric
value -> evaluated asRange
0..value
@param seed: [
nil
,Numeric
] initialize the generator state for reproducibility. (default:nil
)-
nil
-> use system entropy viaSecureRandom
to generate 256 bits of initial state. -
Numeric
value -> calculate SHA256 hash of value to use as the initial state.
-
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/xoroshiro.rb', line 63 def initialize(range = nil, seed: nil) set_state(Xoroshiro.gen_seed_state(seed)) gen_method = method(:each_u_range) case range when nil gen_method = method(:each_u) when Numeric @range = 0..range when Range @range = range else warn "Invalid range argument: #{range}" gen_method = method(:each_u) end @generator = gen_method.call end |
Instance Method Details
#each ⇒ Object
Yields random values determined by the range argument of initialize
.
83 84 85 |
# File 'lib/xoroshiro.rb', line 83 def each @generator end |
#get_state ⇒ Object
Retrieve the current 256 bit state of the generator. Complement to set_state
.
46 47 48 49 50 51 52 53 54 |
# File 'ext/xoroshiro/xoroshiro.c', line 46
static VALUE get_state(VALUE self) {
seed_struct* seed_values;
Data_Get_Struct(self, seed_struct, seed_values);
VALUE state = rb_ary_new();
for (uint32_t i = 0; i < seed_values->size; ++i) {
rb_ary_push(state, ULL2NUM(seed_values->seed[i]));
}
return state;
}
|
#jump ⇒ Object
Update the state to the equivalent of 2^128 calls to rand(). This can be used to generate 2^128 non-overlapping subsequences for parallel computations.
61 62 63 64 65 66 |
# File 'ext/xoroshiro/xoroshiro.c', line 61 static VALUE do_jump(VALUE self) { seed_struct* seed_values; Data_Get_Struct(self, seed_struct, seed_values); jump(seed_values); return self; } |
#long_jump ⇒ Object
Update the state to the equivalent of 2^192 calls to rand(). This can be used to generate 2^64 non-overlapping subsequences for parallel computations.
73 74 75 76 77 78 |
# File 'ext/xoroshiro/xoroshiro.c', line 73 static VALUE do_long_jump(VALUE self) { seed_struct* seed_values; Data_Get_Struct(self, seed_struct, seed_values); long_jump(seed_values); return self; } |
#rand(*args) ⇒ Object
Generate a random value as specified by args
.
- Arguments
-
@param args [
nil
,Range
,Numeric
] specify the range and type of the generated value. (default:nil
)-
nil
-> generate a Uniform(0,1)Float
value -
Range
-> generate a uniformly distributed value within the range of type:-
if both bounds are
Integer
->Integer
-
otherwise ->
Float
-
-
Numeric
value -> evaluated asRange
(0..value)
-
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'ext/xoroshiro/xoroshiro.c', line 95
static VALUE rand_method(int argc, VALUE* argv, VALUE self) {
seed_struct* seed_values;
Data_Get_Struct(self, seed_struct, seed_values);
VALUE argument;
rb_scan_args(argc, argv, "01", &argument);
VALUE outcome = Qnil;
if (rb_obj_is_kind_of(argument, rb_cRange)) {
VALUE rb_beg;
VALUE rb_end;
int excl;
if (!rb_range_values(argument, &rb_beg, &rb_end, &excl)) return Qnil;
if (NIL_P(rb_beg) || NIL_P(rb_end)) return Qnil;
if (rb_obj_is_kind_of(rb_beg, rb_cNumeric) && rb_obj_is_kind_of(rb_end, rb_cNumeric)) {
if (RB_FLOAT_TYPE_P(rb_beg) || RB_FLOAT_TYPE_P(rb_end)) {
double begin = NUM2DBL(rb_beg);
double drange = NUM2DBL(rb_end) - begin;
outcome = DBL2NUM(begin + next_double(seed_values) * drange);
} else {
int64_t begin = NUM2LL(rb_beg);
int64_t end = NUM2LL(rb_end);
int64_t irange = end - begin;
if (!excl) {
irange += 1;
}
if (irange >= 0) outcome = LL2NUM(begin + nearlydivisionless(irange, seed_values));
}
}
return outcome;
} else {
switch (TYPE(argument)) {
case T_NIL:
outcome = DBL2NUM(next_double(seed_values));
break;
case T_FLOAT:
outcome = DBL2NUM(next_double(seed_values) * NUM2DBL(argument));
break;
case T_FIXNUM: {
int64_t upper_lim = NUM2LL(argument);
if (upper_lim > 0) outcome = ULL2NUM(nearlydivisionless(upper_lim, seed_values));
break;
}
case T_BIGNUM: {
uint64_t upper_lim = NUM2ULL(argument);
outcome = ULL2NUM(nearlydivisionless(upper_lim, seed_values));
break;
}
}
return outcome;
}
}
|
#set_state(seeds) ⇒ Object
Explicitly set the 256 bit state of the generator. Complement to get_state
.
- Arguments
-
@param seeds [Array of 4 Integers]
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'ext/xoroshiro/xoroshiro.c', line 23
static VALUE set_state(VALUE self, VALUE seeds) {
Check_Type(seeds, T_ARRAY);
long seedsize = RARRAY_LEN(seeds);
if (seedsize != 4) {
rb_raise(rb_eTypeError, "set_state: Four integer seed values required");
}
seed_struct* seed_values;
Data_Get_Struct(self, seed_struct, seed_values);
seed_values->size = (uint32_t) seedsize;
seed_values->seed = (uint64_t *) malloc(seed_values->size * sizeof(uint64_t));
for (uint32_t i = 0; i < seedsize; ++i) {
seed_values->seed[i] = NUM2ULL(rb_ary_entry(seeds, i));
}
return self;
}
|