Advertisement
hoewarden

Untitled

Sep 28th, 2019
731
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 2.56 KB | None | 0 0
  1. // implementing mystical rand5() using existing library
  2. fn rand5() -> u64 {
  3.     rand::random::<u64>() % 5
  4. }
  5.  
  6. #[macro_use]
  7. extern crate lazy_static;
  8. // static global array of 1, 5, 25, 125, ...
  9. lazy_static! {
  10.     static ref DANGER : u64 = std::u64::MAX / 5;
  11.     static ref POWER5: Vec<u64> = {
  12.         let mut v = Vec::<u64>::with_capacity(30);
  13.         let mut x = 1;
  14.         loop {
  15.             v.push(x);
  16.             if x > *DANGER {
  17.                 v.shrink_to_fit();
  18.                 return v;
  19.             }
  20.             x *= 5;
  21.         }
  22.     };
  23. }
  24.  
  25. struct Generator {
  26.     a : u64,
  27.     b : u64,
  28.     p : usize, // denominator is 5^p = POWER5[p]
  29.     // just statistics...
  30.     entropy_input : f64,
  31.     entropy_output : f64,
  32. }
  33.  
  34. impl Generator {
  35.     fn new() -> Generator {
  36.         Generator{
  37.             a : 0,
  38.             b : 1,
  39.             p : 0,
  40.             entropy_input : 0.0,
  41.             entropy_output : 0.0,
  42.         }
  43.     }
  44.  
  45.     fn rand(&mut self, n : u32) -> u32 {
  46.         let n = n as u64;
  47.         if (self.b as f64) * (n as f64) > (std::u64::MAX as f64) {
  48.             self.cool_down();
  49.         }
  50.         // now drill down
  51.         loop {
  52.             let res_before_a = self.a * n / POWER5[self.p]; // can optimize this division out
  53.             let res_before_b = self.b * n / POWER5[self.p];
  54.             if res_before_a == res_before_b {
  55.                 // our [a/5^p; b/5^p) interval is inside [i/n; (i+1)/n) interval
  56.                 self.a = self.a * n - res_before_a * POWER5[self.p];    
  57.                 self.b = self.b * n - res_before_b * POWER5[self.p];    
  58.                 self.entropy_output += (n as f64).log(2.0);
  59.                 return res_before_b as u32;
  60.             } else {
  61.                 // we need go deeper
  62.                 if self.b * n > *DANGER {
  63.                     self.cool_down();
  64.                 }
  65.                 let r5 = rand5();
  66.                 self.entropy_input += 5f64.log(2.0);
  67.                 let b_a = self.b - self.a;
  68.                 self.b = self.a * 5 + (r5 + 1) * b_a;
  69.                 self.a = self.a * 5 + r5 * b_a;
  70.                 self.p += 1;
  71.             }
  72.         }
  73.     }
  74.  
  75.     fn cool_down(&mut self) {
  76.         self.a = 0;
  77.         self.b = 1;
  78.         self.p = 0;
  79.         print!("*");
  80.     }
  81. }
  82.  
  83. fn main() {
  84.     let mut gen = Generator::new();
  85.     for _i in 0..1000 {
  86.         print!("{} ", gen.rand(rand::random::<u32>() % 1000 + 2));
  87.     }
  88.     println!("");
  89.     println!("Entropy consumed: {} bits", gen.entropy_input);
  90.     println!("Entropy produced: {} bits", gen.entropy_output);
  91. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement