@@ -137,6 +137,13 @@ impl Isaac64Rng {
137137 /// - We fill `rsl` backwards. The reference implementation reads values
138138 /// from `rsl` in reverse. We read them in the normal direction, to make
139139 /// `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`.
140147 fn isaac64 ( & mut self ) {
141148 self . c += w ( 1 ) ;
142149 // abbreviations
@@ -186,26 +193,48 @@ impl Isaac64Rng {
186193
187194 self . a = a;
188195 self . b = b;
189- self . index = 0 ;
196+ self . index = 1 ;
190197 }
191198}
192199
193200impl Rng for Isaac64Rng {
194201 #[ inline]
195202 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
197226 }
198227
199228 #[ inline]
200229 fn next_u64 ( & mut self ) -> u64 {
201- let mut index = self . index as usize ;
230+ let mut index = self . index as usize >> 1 ;
202231 if index >= RAND_SIZE {
203232 self . isaac64 ( ) ;
204233 index = 0 ;
205234 }
206235
207236 let value = self . rsl [ index] ;
208- self . index += 1 ;
237+ self . index += 2 ;
209238 value
210239 }
211240
@@ -217,15 +246,15 @@ impl Rng for Isaac64Rng {
217246 fn fill_bytes ( & mut self , dest : & mut [ u8 ] ) {
218247 let mut read_len = 0 ;
219248 while read_len < dest. len ( ) {
220- if self . index as usize >= RAND_SIZE {
249+ if ( self . index as usize >> 1 ) >= RAND_SIZE {
221250 self . isaac64 ( ) ;
222251 }
223252
224253 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 ) ..] ,
226255 & mut dest[ read_len..] ) ;
227256
228- self . index += consumed_u64 as u32 ;
257+ self . index += consumed_u64 as u32 * 2 ;
229258 read_len += filled_u8;
230259 }
231260 }
@@ -385,20 +414,12 @@ mod test {
385414 let mut rng1 = Isaac64Rng :: from_seed ( seed) ;
386415 let v = ( 0 ..10 ) . map ( |_| rng1. next_u32 ( ) ) . collect :: < Vec < _ > > ( ) ;
387416 // 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
396417 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 ] ) ;
402423 }
403424
404425 #[ test]
0 commit comments