@@ -51,36 +51,23 @@ pub struct Exp12Result {
5151 pub rows : Vec < Exp12Row > ,
5252}
5353
54- #[ derive( Debug , Clone ) ]
55- struct Lcg64 {
56- state : u64 ,
54+ fn uniform_u53 ( seed : u64 , trial_idx : usize , bit_idx : usize ) -> f64 {
55+ let mut x = seed
56+ ^ ( ( trial_idx as u64 ) . wrapping_mul ( 0x9E37_79B9_7F4A_7C15 ) )
57+ ^ ( ( bit_idx as u64 ) . wrapping_mul ( 0xBF58_476D_1CE4_E5B9 ) ) ;
58+ x ^= x >> 30 ;
59+ x = x. wrapping_mul ( 0xBF58_476D_1CE4_E5B9 ) ;
60+ x ^= x >> 27 ;
61+ x = x. wrapping_mul ( 0x94D0_49BB_1331_11EB ) ;
62+ x ^= x >> 31 ;
63+ let v = x >> 11 ;
64+ ( v as f64 ) * ( 1.0 / ( ( 1u64 << 53 ) as f64 ) )
5765}
5866
59- impl Lcg64 {
60- fn new ( seed : u64 ) -> Self {
61- Self {
62- state : seed ^ 0x9E37_79B9_7F4A_7C15 ,
63- }
64- }
65-
66- fn next_u64 ( & mut self ) -> u64 {
67- self . state = self
68- . state
69- . wrapping_mul ( 6364136223846793005 )
70- . wrapping_add ( 1442695040888963407 ) ;
71- self . state
72- }
73-
74- fn next_f64 ( & mut self ) -> f64 {
75- let v = self . next_u64 ( ) >> 11 ;
76- ( v as f64 ) * ( 1.0 / ( ( 1u64 << 53 ) as f64 ) )
77- }
78- }
79-
80- fn binomial_sample ( n : usize , p : f64 , rng : & mut Lcg64 ) -> usize {
67+ fn binomial_sample ( n : usize , p : f64 , seed : u64 , trial_idx : usize ) -> usize {
8168 let mut s = 0usize ;
82- for _ in 0 ..n {
83- if rng . next_f64 ( ) < p {
69+ for bit_idx in 0 ..n {
70+ if uniform_u53 ( seed , trial_idx , bit_idx ) < p {
8471 s += 1 ;
8572 }
8673 }
@@ -93,16 +80,14 @@ pub async fn run_exp12(cfg: &Exp12Config) -> anyhow::Result<Exp12Result> {
9380 }
9481
9582 let mut rows = Vec :: with_capacity ( cfg. scenarios . len ( ) ) ;
96- let mut rng = Lcg64 :: new ( cfg. seed ) ;
97-
9883 for scenario in & cfg. scenarios {
9984 if !scenario. psplit . is_finite ( ) || !( 0.0 ..=1.0 ) . contains ( & scenario. psplit ) {
10085 anyhow:: bail!( "psplit must be finite and within [0,1]" ) ;
10186 }
10287
10388 let mut leaked = Vec :: with_capacity ( cfg. trials ) ;
104- for _ in 0 ..cfg. trials {
105- let s = binomial_sample ( scenario. n , scenario. psplit , & mut rng ) ;
89+ for trial_idx in 0 ..cfg. trials {
90+ let s = binomial_sample ( scenario. n , scenario. psplit , cfg . seed , trial_idx ) ;
10691 leaked. push ( cfg. topic_budget_bits + s) ;
10792 }
10893
0 commit comments