@@ -136,6 +136,13 @@ impl Isaac64Rng {
136
136
/// - We fill `rsl` backwards. The reference implementation reads values
137
137
/// from `rsl` in reverse. We read them in the normal direction, to make
138
138
/// `fill_bytes` a memcopy. To maintain compatibility we fill in reverse.
139
+ /// - We store `index` as if `rsl` contains `u32`'s instead of `u64`'s, plus
140
+ /// one. This way we can make more efficient use of the generated results
141
+ /// in `next_u32`.
142
+ /// For `next_u32` the correct index is `index - 1`.
143
+ /// For `next_u64` the correct index is `index >> 1`, which also takes
144
+ /// care of any alignment issues that could arise if `next_u64` was called
145
+ /// after `next_u32`.
139
146
fn isaac64 ( & mut self ) {
140
147
self . c += w ( 1 ) ;
141
148
// abbreviations
@@ -185,41 +192,63 @@ impl Isaac64Rng {
185
192
186
193
self . a = a;
187
194
self . b = b;
188
- self . index = 0 ;
195
+ self . index = 1 ;
189
196
}
190
197
}
191
198
192
199
impl Rng for Isaac64Rng {
193
200
#[ inline]
194
201
fn next_u32 ( & mut self ) -> u32 {
195
- self . next_u64 ( ) as u32
202
+ // Using a local variable for `index`, and checking the size avoids a
203
+ // bounds check later on.
204
+ let mut index = self . index as usize - 1 ;
205
+ if index >= RAND_SIZE * 2 {
206
+ self . isaac64 ( ) ;
207
+ index = 0 ;
208
+ }
209
+
210
+ let value;
211
+ if cfg ! ( target_endian = "little" ) {
212
+ // Index as if this is a u32 slice.
213
+ let rsl = unsafe { & * ( & mut self . rsl as * mut [ u64 ; RAND_SIZE ]
214
+ as * mut [ u32 ; RAND_SIZE * 2 ] ) } ;
215
+ value = rsl[ index] ;
216
+ } else {
217
+ // Index into the u64 slice, rotate and truncate the result.
218
+ // Works always, also on big-endian systems, but is slower.
219
+ let tmp = self . rsl [ index >> 1 ] ;
220
+ value = tmp as u32 ;
221
+ self . rsl [ index >> 1 ] = tmp. rotate_right ( 32 ) ;
222
+ }
223
+ self . index += 1 ;
224
+ value
196
225
}
197
226
198
227
#[ inline]
199
228
fn next_u64 ( & mut self ) -> u64 {
200
- let mut index = self . index as usize ;
229
+ let mut index = self . index as usize >> 1 ;
201
230
if index >= RAND_SIZE {
202
231
self . isaac64 ( ) ;
203
232
index = 0 ;
204
233
}
205
234
206
235
let value = self . rsl [ index] ;
207
- self . index += 1 ;
236
+ self . index += 2 ;
208
237
value
209
238
}
210
239
211
240
fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
212
241
let mut read_len = 0 ;
213
242
while read_len < dest. len ( ) {
214
- if self . index as usize >= RAND_SIZE {
243
+ if ( self . index as usize >> 1 ) >= RAND_SIZE {
215
244
self . isaac64 ( ) ;
216
245
}
217
246
218
247
let ( consumed_u64, filled_u8) =
219
- impls:: fill_via_u64_chunks ( & mut self . rsl [ ( self . index as usize ) ..] ,
248
+ impls:: fill_via_u64_chunks ( & mut self . rsl [ ( self . index as usize >> 1 ) ..] ,
220
249
& mut dest[ read_len..] ) ;
221
250
222
- self . index += consumed_u64 as u32 ;
251
+ self . index += consumed_u64 as u32 * 2 ;
223
252
read_len += filled_u8;
224
253
}
225
254
}
@@ -386,20 +415,12 @@ mod test {
386
415
let mut rng1 = Isaac64Rng :: from_seed ( seed) ;
387
416
let v = ( 0 ..10 ) . map ( |_| rng1. next_u32 ( ) ) . collect :: < Vec < _ > > ( ) ;
388
417
// Subset of above values, as an LE u32 sequence
389
- // TODO: switch to this sequence?
390
- // assert_eq!(v,
391
- // [141028748, 127386717,
392
- // 1058730652, 3347555894,
393
- // 851491469, 4039984500,
394
- // 2692730210, 288449107,
395
- // 646103879, 2782923823]);
396
- // Subset of above values, using only low-half of each u64
397
418
assert_eq ! ( v,
398
- [ 141028748 , 1058730652 ,
399
- 851491469 , 2692730210 ,
400
- 646103879 , 4195642895 ,
401
- 2836348583 , 1312677241 ,
402
- 999139615 , 253604626 ] ) ;
419
+ [ 141028748 , 127386717 ,
420
+ 1058730652 , 3347555894 ,
421
+ 851491469 , 4039984500 ,
422
+ 2692730210 , 288449107 ,
423
+ 646103879 , 2782923823 ] ) ;
403
424
}
404
425
405
426
#[ test]
0 commit comments