@@ -207,20 +207,13 @@ impl<T: Rand> Rand for @T {
207
207
fn rand < R : Rng > ( rng : & R ) -> @T { @rng. gen ( ) }
208
208
}
209
209
210
- #[ allow( non_camel_case_types) ] // runtime type
211
- pub enum rust_rng { }
212
-
213
210
#[ abi = "cdecl" ]
214
211
pub mod rustrt {
215
212
use libc:: size_t;
216
- use super :: rust_rng;
217
213
218
214
pub extern {
219
215
unsafe fn rand_seed_size ( ) -> size_t ;
220
216
unsafe fn rand_gen_seed ( buf : * mut u8 , sz : size_t ) ;
221
- unsafe fn rand_new_seeded ( buf : * u8 , sz : size_t ) -> * rust_rng ;
222
- unsafe fn rand_next ( rng : * rust_rng ) -> u32 ;
223
- unsafe fn rand_free ( rng : * rust_rng ) ;
224
217
}
225
218
}
226
219
@@ -566,66 +559,179 @@ pub fn rng() -> IsaacRng {
566
559
IsaacRng :: new ( )
567
560
}
568
561
569
- pub struct IsaacRng {
570
- priv rng: * rust_rng ,
571
- }
562
+ static RAND_SIZE_LEN : u32 = 8 ;
563
+ static RAND_SIZE : u32 = 1 << RAND_SIZE_LEN ;
572
564
573
- impl Drop for IsaacRng {
574
- fn finalize ( & self ) {
575
- unsafe {
576
- rustrt:: rand_free ( self . rng ) ;
577
- }
578
- }
565
+ /// A random number generator that uses the [ISAAC
566
+ /// algorithm](http://en.wikipedia.org/wiki/ISAAC_%28cipher%29).
567
+ pub struct IsaacRng {
568
+ priv mut cnt: u32 ,
569
+ priv mut rsl: [ u32 , .. RAND_SIZE ] ,
570
+ priv mut mem: [ u32 , .. RAND_SIZE ] ,
571
+ priv mut a: u32 ,
572
+ priv mut b: u32 ,
573
+ priv mut c: u32
579
574
}
580
575
581
576
pub impl IsaacRng {
582
- priv fn from_rust_rng ( rng : * rust_rng ) -> IsaacRng {
583
- IsaacRng {
584
- rng : rng
585
- }
586
- }
587
-
588
- /// Create an ISAAC random number generator with a system specified seed
577
+ /// Create an ISAAC random number generator with a random seed.
589
578
fn new ( ) -> IsaacRng {
590
579
IsaacRng :: new_seeded ( seed ( ) )
591
580
}
592
581
593
- /**
594
- * Create a random number generator using the specified seed. A generator
595
- * constructed with a given seed will generate the same sequence of values as
596
- * all other generators constructed with the same seed. The seed may be any
597
- * length.
598
- */
582
+ /// Create an ISAAC random number generator with a seed. This can be any
583
+ /// length, although the maximum number of bytes used is 1024 and any more
584
+ /// will be silently ignored. A generator constructed with a given seed
585
+ /// will generate the same sequence of values as all other generators
586
+ /// constructed with the same seed.
599
587
fn new_seeded ( seed : & [ u8 ] ) -> IsaacRng {
600
- unsafe {
601
- do vec:: as_imm_buf ( seed) |p, sz| {
602
- IsaacRng :: from_rust_rng ( rustrt:: rand_new_seeded ( p, sz as size_t ) )
588
+ let mut rng = IsaacRng {
589
+ cnt : 0 ,
590
+ rsl : [ 0 , .. RAND_SIZE ] ,
591
+ mem : [ 0 , .. RAND_SIZE ] ,
592
+ a : 0 , b : 0 , c : 0
593
+ } ;
594
+
595
+ let array_size = sys:: size_of_val ( & rng. rsl ) ;
596
+ let copy_length = cmp:: min ( array_size, seed. len ( ) ) ;
597
+
598
+ // manually create a &mut [u8] slice of randrsl to copy into.
599
+ let dest = unsafe { cast:: transmute ( ( & mut rng. rsl , array_size) ) } ;
600
+ vec:: bytes:: copy_memory ( dest, seed, copy_length) ;
601
+ rng. init ( true ) ;
602
+ rng
603
+ }
604
+
605
+ /// Create an ISAAC random number generator using the default
606
+ /// fixed seed.
607
+ fn new_unseeded ( ) -> IsaacRng {
608
+ let mut rng = IsaacRng {
609
+ cnt : 0 ,
610
+ rsl : [ 0 , .. RAND_SIZE ] ,
611
+ mem : [ 0 , .. RAND_SIZE ] ,
612
+ a : 0 , b : 0 , c : 0
613
+ } ;
614
+ rng. init ( false ) ;
615
+ rng
616
+ }
617
+
618
+ /// Initialises `self`. If `use_rsl` is true, then use the current value
619
+ /// of `rsl` as a seed, otherwise construct one algorithmically (not
620
+ /// randomly).
621
+ priv fn init( & self , use_rsl : bool ) {
622
+ macro_rules! init_mut_many (
623
+ ( $( $var: ident ) ,* = $val: expr ) => {
624
+ let mut $( $var = $val ) ,* ;
625
+ }
626
+ ) ;
627
+ init_mut_many ! ( a, b, c, d, e, f, g, h = 0x9e3779b9 ) ;
628
+
629
+
630
+ macro_rules! mix(
631
+ ( ) => { {
632
+ a^=b<<11 ; d+=a; b+=c;
633
+ b^=c>>2 ; e+=b; c+=d;
634
+ c^=d<<8 ; f+=c; d+=e;
635
+ d^=e>>16 ; g+=d; e+=f;
636
+ e^=f<<10 ; h+=e; f+=g;
637
+ f^=g>>4 ; a+=f; g+=h;
638
+ g^=h<<8 ; b+=g; h+=a;
639
+ h^=a>>9 ; c+=h; a+=b;
640
+ } }
641
+ ) ;
642
+
643
+ for 4 . times { mix!( ) ; }
644
+
645
+ if use_rsl {
646
+ macro_rules! memloop (
647
+ ( $arr: expr) => { {
648
+ for u32:: range_step( 0 , RAND_SIZE , 8 ) |i| {
649
+ a+=$arr[ i ] ; b+=$arr[ i+1 ] ;
650
+ c+=$arr[ i+2 ] ; d+=$arr[ i+3 ] ;
651
+ e+=$arr[ i+4 ] ; f+=$arr[ i+5 ] ;
652
+ g+=$arr[ i+6 ] ; h+=$arr[ i+7 ] ;
653
+ mix ! ( ) ;
654
+ self . mem[ i ] =a; self . mem[ i+1 ] =b;
655
+ self . mem[ i+2 ] =c; self . mem[ i+3 ] =d;
656
+ self . mem[ i+4 ] =e; self . mem[ i+5 ] =f;
657
+ self . mem[ i+6 ] =g; self . mem[ i+7 ] =h;
658
+ }
659
+ } }
660
+ ) ;
661
+
662
+ memloop ! ( self . rsl) ;
663
+ memloop ! ( self . mem) ;
664
+ } else {
665
+ for u32:: range_step( 0 , RAND_SIZE , 8 ) |i| {
666
+ mix ! ( ) ;
667
+ self . mem[ i ] =a; self . mem[ i+1 ] =b;
668
+ self . mem[ i+2 ] =c; self . mem[ i+3 ] =d;
669
+ self . mem[ i+4 ] =e; self . mem[ i+5 ] =f;
670
+ self . mem[ i+6 ] =g; self . mem[ i+7 ] =h;
603
671
}
604
672
}
673
+
674
+ self . isaac( ) ;
605
675
}
606
- }
607
676
608
- impl Rng for IsaacRng {
609
- pub fn next ( & self ) -> u32 {
610
- unsafe {
611
- return rustrt:: rand_next ( self . rng ) ;
677
+ /// Refills the output buffer (`self.rsl`)
678
+ priv fn isaac( & self ) {
679
+ self . c += 1 ;
680
+ // abbreviations
681
+ let mut a = self . a, b = self . b + self . c;
682
+ let mem = & mut self . mem;
683
+ let rsl = & mut self . rsl;
684
+
685
+ static midpoint: uint = RAND_SIZE as uint / 2 ;
686
+
687
+ macro_rules! ind ( ( $x: expr) => { mem[ ( $x >> 2 ) & ( RAND_SIZE - 1 ) ] } ) ;
688
+ macro_rules! rngstep(
689
+ ( $j: expr, $shift: expr) => { {
690
+ let base = base + $j;
691
+ let mix = if $shift < 0 {
692
+ a >> -$shift as uint
693
+ } else {
694
+ a << $shift as uint
695
+ } ;
696
+
697
+ let x = mem[ base + mr_offset ] ;
698
+ a = ( a ^ mix ) + mem[ base + m2_offset ] ;
699
+ let y = ind ! ( x) + a + b ;
700
+ mem[ base + mr_offset ] = y ;
701
+
702
+ b = ind ! ( y >> RAND_SIZE_LEN ) + x ;
703
+ rsl[ base + mr_offset ] = b ;
704
+ } }
705
+ ) ;
706
+
707
+ for [ ( 0 , midpoint ) , ( midpoint , 0 ) ] . each |& ( mr_offset , m2_offset ) | {
708
+ for uint:: range_step ( 0 , midpoint , 4 ) |base| {
709
+ rngstep ! ( 0 , 13 ) ;
710
+ rngstep ! ( 1 , -6 ) ;
711
+ rngstep ! ( 2 , 2 ) ;
712
+ rngstep ! ( 3 , -16 ) ;
713
+ }
612
714
}
715
+
716
+ self . a = a;
717
+ self . b = b;
718
+ self . cnt = RAND_SIZE ;
613
719
}
614
720
}
615
721
616
- /// Create a new random seed for IsaacRng::new_seeded
617
- pub fn seed ( ) -> ~[ u8 ] {
618
- unsafe {
619
- let n = rustrt:: rand_seed_size ( ) as uint ;
620
- let mut s = vec:: from_elem ( n, 0_u8 ) ;
621
- do vec:: as_mut_buf ( s) |p, sz| {
622
- rustrt:: rand_gen_seed ( p, sz as size_t )
722
+ impl Rng for IsaacRng {
723
+ #[ inline( always) ]
724
+ fn next ( & self ) -> u32 {
725
+ if self . cnt == 0 {
726
+ // make some more numbers
727
+ self . isaac ( ) ;
623
728
}
624
- s
729
+ self . cnt -= 1 ;
730
+ self . rsl[ self . cnt]
625
731
}
626
732
}
627
733
628
- struct XorShiftRng {
734
+ pub struct XorShiftRng {
629
735
priv mut x : u32,
630
736
priv mut y : u32,
631
737
priv mut z : u32,
@@ -660,7 +766,18 @@ pub impl XorShiftRng {
660
766
fn new_seeded ( x : u32 , y : u32 , z : u32 , w : u32 ) -> XorShiftRng {
661
767
XorShiftRng { x : x, y : y, z : z, w : w }
662
768
}
769
+ }
663
770
771
+ /// Create a new random seed.
772
+ pub fn seed ( ) -> ~[ u8 ] {
773
+ unsafe {
774
+ let n = rustrt:: rand_seed_size ( ) as uint ;
775
+ let mut s = vec:: from_elem ( n, 0_u8 ) ;
776
+ do vec:: as_mut_buf ( s) |p, sz| {
777
+ rustrt:: rand_gen_seed ( p, sz as size_t )
778
+ }
779
+ s
780
+ }
664
781
}
665
782
666
783
// used to make space in TLS for a random number generator
@@ -879,6 +996,45 @@ mod tests {
879
996
( u8 , i8 , u16 , i16 , u32 , i32 , u64 , i64 ) ,
880
997
( f32 , ( f64 , ( float , ) ) ) ) = random ( ) ;
881
998
}
999
+
1000
+ #[ test]
1001
+ fn compare_isaac_implementation ( ) {
1002
+ // This is to verify that the implementation of the ISAAC rng is
1003
+ // correct (i.e. matches the output of the upstream implementation,
1004
+ // which is in the runtime)
1005
+ use vec;
1006
+ use libc:: size_t;
1007
+
1008
+ #[ abi = "cdecl" ]
1009
+ mod rustrt {
1010
+ use libc:: size_t;
1011
+
1012
+ #[ allow( non_camel_case_types) ] // runtime type
1013
+ pub enum rust_rng { }
1014
+
1015
+ pub extern {
1016
+ unsafe fn rand_new_seeded ( buf : * u8 , sz : size_t ) -> * rust_rng ;
1017
+ unsafe fn rand_next ( rng : * rust_rng ) -> u32 ;
1018
+ unsafe fn rand_free ( rng : * rust_rng ) ;
1019
+ }
1020
+ }
1021
+
1022
+ // run against several seeds
1023
+ for 10 . times {
1024
+ unsafe {
1025
+ let seed = super :: seed ( ) ;
1026
+ let rt_rng = do vec:: as_imm_buf ( seed) |p, sz| {
1027
+ rustrt:: rand_new_seeded ( p, sz as size_t )
1028
+ } ;
1029
+ let rng = IsaacRng :: new_seeded ( seed) ;
1030
+
1031
+ for 10000 . times {
1032
+ assert_eq!( rng. next( ) , rustrt : : rand_next( rt_rng) ) ;
1033
+ }
1034
+ rustrt:: rand_free( rt_rng) ;
1035
+ }
1036
+ }
1037
+ }
882
1038
}
883
1039
884
1040
0 commit comments