@@ -96,6 +96,7 @@ pub struct IsaacRng {
96
96
}
97
97
98
98
// Cannot be derived because [u32; 256] does not implement Clone
99
+ // FIXME: remove once RFC 2000 gets implemented
99
100
impl Clone for IsaacRng {
100
101
fn clone ( & self ) -> IsaacRng {
101
102
IsaacRng {
@@ -115,62 +116,21 @@ impl fmt::Debug for IsaacRng {
115
116
}
116
117
}
117
118
118
- fn mix ( a : & mut w32 , b : & mut w32 , c : & mut w32 , d : & mut w32 ,
119
- e : & mut w32 , f : & mut w32 , g : & mut w32 , h : & mut w32 ) {
120
- * a ^= * b << 11 ; * d += * a; * b += * c;
121
- * b ^= * c >> 2 ; * e += * b; * c += * d;
122
- * c ^= * d << 8 ; * f += * c; * d += * e;
123
- * d ^= * e >> 16 ; * g += * d; * e += * f;
124
- * e ^= * f << 10 ; * h += * e; * f += * g;
125
- * f ^= * g >> 4 ; * a += * f; * g += * h;
126
- * g ^= * h << 8 ; * b += * g; * h += * a;
127
- * h ^= * a >> 9 ; * c += * h; * a += * b;
128
- }
129
-
130
119
impl IsaacRng {
131
120
/// Creates an ISAAC random number generator using an u64 as seed.
132
121
/// If `seed == 0` this will produce the same stream of random numbers as
133
122
/// the reference implementation when used unseeded.
134
123
pub fn new_from_u64 ( seed : u64 ) -> IsaacRng {
135
- let mut a = w ( 0x1367df5a ) ;
136
- let mut b = w ( 0x95d90059 ) ;
137
- let mut c = w ( 0xc3163e4b ) ;
138
- let mut d = w ( 0x0f421ad8 ) ;
139
- let mut e = w ( 0xd92a4a78 ) ;
140
- let mut f = w ( 0xa51a3c49 ) ;
141
- let mut g = w ( 0xc4efea1b ) ;
142
- let mut h = w ( 0x30609119 ) ;
143
-
144
- let mut mem = [ w ( 0 ) ; RAND_SIZE ] ;
145
-
146
- a += w ( seed as u32 ) ;
147
- b += w ( ( seed >> 32 ) as u32 ) ;
148
-
149
- for i in ( 0 ..RAND_SIZE /8 ) . map ( |i| i * 8 ) {
150
- mix ( & mut a, & mut b, & mut c, & mut d, & mut e, & mut f, & mut g, & mut h) ;
151
- mem[ i ] = a; mem[ i+1 ] = b;
152
- mem[ i+2 ] = c; mem[ i+3 ] = d;
153
- mem[ i+4 ] = e; mem[ i+5 ] = f;
154
- mem[ i+6 ] = g; mem[ i+7 ] = h;
155
- }
124
+ let mut key = [ w ( 0 ) ; RAND_SIZE ] ;
125
+ key[ 0 ] = w ( seed as u32 ) ;
126
+ key[ 1 ] += w ( ( seed >> 32 ) as u32 ) ;
127
+ // Initialize with only one pass.
156
128
// A second pass does not improve the quality here, because all of
157
129
// the seed was already available in the first round.
158
130
// Not doing the second pass has the small advantage that if `seed == 0`
159
131
// this method produces exactly the same state as the reference
160
132
// implementation when used unseeded.
161
-
162
- let mut rng = IsaacRng {
163
- rsl : [ w ( 0 ) ; RAND_SIZE ] ,
164
- mem : mem,
165
- a : w ( 0 ) ,
166
- b : w ( 0 ) ,
167
- c : w ( 0 ) ,
168
- cnt : 0 ,
169
- } ;
170
-
171
- // Prepare the first set of results
172
- rng. isaac ( ) ;
173
- rng
133
+ init ( key, 1 )
174
134
}
175
135
176
136
/// Refills the output buffer (`self.rsl`)
@@ -278,7 +238,7 @@ impl Rng for IsaacRng {
278
238
}
279
239
}
280
240
281
- /// Creates a new ISAAC-64 random number generator.
241
+ /// Creates a new ISAAC random number generator.
282
242
///
283
243
/// The author Bob Jenkins describes how to best initialize ISAAC here:
284
244
/// https://rt.cpan.org/Public/Bug/Display.html?id=64324
@@ -304,7 +264,7 @@ impl Rng for IsaacRng {
304
264
/// mixes it, and combines that with the next 32 bytes, et cetera. Then loops
305
265
/// over all the elements the same way a second time."
306
266
#[ inline]
307
- fn init ( key : [ w32 ; RAND_SIZE ] ) -> IsaacRng {
267
+ fn init ( mut mem : [ w32 ; RAND_SIZE ] , rounds : u32 ) -> IsaacRng {
308
268
// These numbers are the result of initializing a...h with the
309
269
// fractional part of the golden ratio in binary (0x9e3779b9)
310
270
// and applying mix() 4 times.
@@ -317,29 +277,23 @@ fn init(key: [w32; RAND_SIZE]) -> IsaacRng {
317
277
let mut g = w ( 0xc4efea1b ) ;
318
278
let mut h = w ( 0x30609119 ) ;
319
279
320
- let mut mem = [ w ( 0 ) ; RAND_SIZE ] ;
321
-
322
- macro_rules! memloop {
323
- ( $arr: expr) => { {
324
- for i in ( 0 ..RAND_SIZE /8 ) . map( |i| i * 8 ) {
325
- a += $arr[ i ] ; b += $arr[ i+1 ] ;
326
- c += $arr[ i+2 ] ; d += $arr[ i+3 ] ;
327
- e += $arr[ i+4 ] ; f += $arr[ i+5 ] ;
328
- g += $arr[ i+6 ] ; h += $arr[ i+7 ] ;
329
- mix( & mut a, & mut b, & mut c, & mut d,
330
- & mut e, & mut f, & mut g, & mut h) ;
331
- mem[ i ] = a; mem[ i+1 ] = b;
332
- mem[ i+2 ] = c; mem[ i+3 ] = d;
333
- mem[ i+4 ] = e; mem[ i+5 ] = f;
334
- mem[ i+6 ] = g; mem[ i+7 ] = h;
335
- }
336
- } }
280
+ // Normally this should do two passes, to make all of the seed effect all
281
+ // of `mem`
282
+ for _ in 0 ..rounds {
283
+ for i in ( 0 ..RAND_SIZE /8 ) . map ( |i| i * 8 ) {
284
+ a += mem[ i ] ; b += mem[ i+1 ] ;
285
+ c += mem[ i+2 ] ; d += mem[ i+3 ] ;
286
+ e += mem[ i+4 ] ; f += mem[ i+5 ] ;
287
+ g += mem[ i+6 ] ; h += mem[ i+7 ] ;
288
+ mix ( & mut a, & mut b, & mut c, & mut d,
289
+ & mut e, & mut f, & mut g, & mut h) ;
290
+ mem[ i ] = a; mem[ i+1 ] = b;
291
+ mem[ i+2 ] = c; mem[ i+3 ] = d;
292
+ mem[ i+4 ] = e; mem[ i+5 ] = f;
293
+ mem[ i+6 ] = g; mem[ i+7 ] = h;
294
+ }
337
295
}
338
296
339
- memloop ! ( key) ;
340
- // Do a second pass to make all of the seed affect all of `mem`
341
- memloop ! ( mem) ;
342
-
343
297
let mut rng = IsaacRng {
344
298
rsl : [ w ( 0 ) ; RAND_SIZE ] ,
345
299
mem : mem,
@@ -354,6 +308,18 @@ fn init(key: [w32; RAND_SIZE]) -> IsaacRng {
354
308
rng
355
309
}
356
310
311
+ fn mix ( a : & mut w32 , b : & mut w32 , c : & mut w32 , d : & mut w32 ,
312
+ e : & mut w32 , f : & mut w32 , g : & mut w32 , h : & mut w32 ) {
313
+ * a ^= * b << 11 ; * d += * a; * b += * c;
314
+ * b ^= * c >> 2 ; * e += * b; * c += * d;
315
+ * c ^= * d << 8 ; * f += * c; * d += * e;
316
+ * d ^= * e >> 16 ; * g += * d; * e += * f;
317
+ * e ^= * f << 10 ; * h += * e; * f += * g;
318
+ * f ^= * g >> 4 ; * a += * f; * g += * h;
319
+ * g ^= * h << 8 ; * b += * g; * h += * a;
320
+ * h ^= * a >> 9 ; * c += * h; * a += * b;
321
+ }
322
+
357
323
impl SeedFromRng for IsaacRng {
358
324
fn from_rng < R : Rng +?Sized > ( other : & mut R ) -> Result < Self > {
359
325
let mut key = [ w ( 0 ) ; RAND_SIZE ] ;
@@ -364,7 +330,7 @@ impl SeedFromRng for IsaacRng {
364
330
other. try_fill ( slice) ?;
365
331
}
366
332
367
- Ok ( init ( key) )
333
+ Ok ( init ( key, 2 ) )
368
334
}
369
335
}
370
336
@@ -385,7 +351,7 @@ impl<'a> SeedableRng<&'a [u32]> for IsaacRng {
385
351
* rsl_elem = w ( seed_elem) ;
386
352
}
387
353
388
- init ( key)
354
+ init ( key, 2 )
389
355
}
390
356
}
391
357
0 commit comments