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