Uh oh!
There was an error while loading. Please reload this page.
Deprecate Rng::gen_weighted_bool - #308
Conversation
3b06ad0 to
b0a5e4fComparedhardy
commented
Mar 17, 2018
I'd prefer to have |
b0a5e4f to
95865cfComparepitdicker
commented
Mar 17, 2018
Implemented I went the easiest route here. Thanks for the suggestion to use my higher precision code here, that gives an excuse to add it 😄. But I'll hold of a little while longer for the range code, we would need to have some discussion first for how to expose it... |
dhardy
left a comment
There was a problem hiding this comment.
Some little doc issues but the code looks good.
| n <= 1 || self.gen_range(0, n) == 0 | ||
| } | ||
| /// Return a bool with a `p` probability of being true. |
| impl Distribution<$ty> for HighPrecision01 { | ||
| /// Generate a floating point number in the open interval `(0, 1)` | ||
| /// (not including either endpoint) with a uniform distribution. |
There was a problem hiding this comment.
I believe this is actually half-open (your old open version used rejection sampling; this code will yield 0 when the sampled u32 is zero). For sample < p this is what we want anyway, so it's just the comment (and possibly the distribution name, I'm not sure on this yet) to change.
| /// Generate a floating point number in the open interval `(0, 1)` | ||
| /// (not including either endpoint) with a uniform distribution. | ||
| /// | ||
| /// This is different from `Uniform` in that it it uses all 32 bits |
| /// use rand::distributions::HighPrecision01; | ||
| /// | ||
| /// let val: f32 = SmallRng::new().sample(HighPrecision01); | ||
| /// println!("f32 from (0,1): {}", val); |
Maybe also document that the smallest non-zero value which can be generated is 0.00000000023283064 = 2.3e-10 (f32) or 0.00000000000000000005421010862427522 I see the distribution |
pitdicker
commented
Mar 18, 2018
Thank you for the close read!
This is not really true, as the precision reduces when the number get higher. And it changes with every (negative) power of two. But I have tried to write some documentation with similar intent. |
dhardy
commented
Mar 18, 2018
Okay, I'm happy for this to be merged. I'd prefer you wait 2-3 days from first opening however in case anyone else has a concern. |
8cd8a5f to
bd5ad92Comparepitdicker
commented
Mar 18, 2018
Added a commit to use |
@dhardy I am getting second thoughts about this implementation of What are out limitations of
When can accuracy be problem when it is too little? I would say that is something very rare. And if you have an algorithm where the result depends on the accuracy of a function you are going to run for more then 2^52 times, I think it is your responsibility to glance over that function and determine if it fits your use. So an accuracy of 2^24 is sometimes too little. 2^52 is very more than enough. Could 2^32 be reasonable? That would allow us to use a single Now I think the following implementation can be interesting, because it turns into a comparison against a constant if fngen_bool(&mutself,p:f64) -> bool{assert!(p >= 0.0 && p <= 1.0);let p_int = (p * core::u32::MAXasf64)asu32;self.gen() < p_int
} |
dhardy
commented
Mar 20, 2018
That sounds reasonable (though it should be 1 in 2^32 bias is probably okay. I have been involved in experiments which may have used around 2^32 Bernoulli samples, but I doubt a single sample error would have had much effect on the results. I was wondering if the equivalent using |
pitdicker
commented
Mar 20, 2018
Thank you, meant to write that... 😄 The equivalent with |
Changed When I tried to benchmark (does it really perform as hoped?) I had some trouble with |
| assert!(p >= 0.0 && p <= 1.0); | ||
| self.sample::<f64, _>(distributions::HighPrecision01) < p | ||
| let p_int = (p * core::u32::MAX as f64) as u32; | ||
| p_int > self.gen() |
There was a problem hiding this comment.
Why swap left-right sides and comparator now?
There was a problem hiding this comment.
Otherwise type inference couldn't figure it out... the alternative was self.gen::<u32>() <= p_int.
There was a problem hiding this comment.
Oh, really? But you need to use >= then.
| /// An RNG recommended when small state, cheap initialization and good | ||
| /// performance are required. The PRNG algorithm in `SmallRng` is choosen to be | ||
| /// performance are required. The PRNG algorithm in `SmallRng` is chosen to be | ||
| /// efficient on the current platform, **without consideration for cryptography |
There was a problem hiding this comment.
Note that Xorshift has good next_u32 performance but not as good next_u64 performance as several other generators. Wait, something's wrong:
test gen_u32_xorshift ... bench: 4,635 ns/iter (+/- 198) = 862 MB/s
test gen_u64_xorshift ... bench: 2,840 ns/iter (+/- 93) = 2816 MB/s
Impossible that next_u64 is faster than next_u32. Anyway, be careful comparing benchmarks for gen_bool: I would imagine it most useful in heavy numerical simulators which would likely either use native 64-bit generators or buffered generators, i.e. a u32 may not be half the price of a u64.
There was a problem hiding this comment.
True, sometimes it will be about half the price, sometimes it just makes no difference.
And you are getting bitten again (I think) by the rust bug with multiple codegen units and benchmarks harness. Can you retry with export RUSTFLAGS="-C codegen-units=1"?
There was a problem hiding this comment.
Interesting; didn't affect most tests (including xorshift bytes with around 900MB/s) but:
test gen_u32_xorshift ... bench: 1,045 ns/iter (+/- 59) = 3827 MB/s
There was a problem hiding this comment.
Actually, that was with another change calling black_box less frequently. Without that I get approx 3000 MB/s. The u64 results only change by about 50MB/s however.
dhardy
left a comment
There was a problem hiding this comment.
It would also be nice if you cleaned this up and pulled the HighPrecision01 stuff into a separate PR, since it's not directly connected any more.
| /// let mut rng = thread_rng(); | ||
| /// println!("{}", rng.gen_bool(1.0 / 3.0)); | ||
| /// ``` | ||
| fn gen_bool(&mut self, p: f64) -> bool { |
There was a problem hiding this comment.
Please add a unit test, at the very least testing that gen_bool(1.0) doesn't panic, or better testing that both 1.0 and 0.0 produce the expected outputs a few times over.
pitdicker
commented
Mar 21, 2018
Can't I sneak in anything quietly? 😄 |
657f86e to
caf811bComparepitdicker
commented
Mar 21, 2018
Rebased, removed the addition of I have added a test for |
pitdicker
commented
Mar 21, 2018
The benchmark results have changed a bit, but finally realistic: A floating point multiply is quite expensive compared to a couple of shifts and XORs, as it should be. Still when |
dhardy
commented
Mar 21, 2018
Looks good, apart from using |
pitdicker
commented
Mar 21, 2018
Ah, the comment was collapsed.
|
dhardy
commented
Mar 21, 2018
No it's not. |
caf811b to
a20c7b1Comparepitdicker
commented
Mar 21, 2018
You are right. What was I confusing it with??? (updated) |
pitdicker
commented
Mar 21, 2018
Ready to merge? |
Deprecate Rng::gen_weighted_bool
As discussed in #293.