Add sample_single to Range#69
Conversation
|
I am seeing some improvements in other benchmarks too: Before: After: |
|
Just added a little optimisation to With |
|
Hmm, not sure how to answer this. I'm not so happy with the use of |
|
With For cryptographic RNG's generating Small fast RNG's mostly need to operate on 64-bit words for good statistical quality. There are some really fast ones where on x86_64 generating So on second thought using |
|
Now I wonder if the optimization of I do like that it removes a complex dependency between |
|
Yes, the optimisation/standalone impl for Not sure what you mean here?
|
|
It would be nice to have something like this as a default implementation: fn sample_single<R: Rng+?Sized>(low: Self::X, high: Self::X, rng: &mut R) -> Self::X {
let range: Self = RangeImpl::new(low, high);
range.sample(rng)
}Then we would not have to add this code when there is no faster / specialized method available for some type (like the one in the tests of this module). But I could not get it to work because Rust can't figure out the types (and neither could I...). |
|
Ah. It's actually quite simple: What the compiler is saying is that you can only construct sized types; here you are trying to construct |
|
I can't really imagine a |
| /// The type sampled by this implementation (output type). | ||
| pub trait RangeImpl: Sized { | ||
| /// The type sampled by this implementation. | ||
| type X: PartialOrd; |
There was a problem hiding this comment.
Why does this type have a PartialOrd bound?
There was a problem hiding this comment.
Um... it might be to allow the low < high check. You can try removing it if you like.
There was a problem hiding this comment.
Now that I looked a bit better at it, SampleRange already has PartialOrd+Sized as trait bounds, which takes care of the low < high check. But the extra bound kind of makes sense: you can't speak about a range between two points if there is not some sort of order between the elements. I will leave it for now.
|
I think this is ready now |
|
Great, thanks! I'm going to assume that the sampling is correct; I glanced over the code but there's so many routines just for ranges now; then there are all the other distributions. I'm thinking an external tool to plot 10'000+ samples for visual inspection might be useful, plus some "synthetic tests" (checking a few inputs produce the expected values). |
|
Now that you mention it, I did not add any tests... The tests for |
|
No, properly testing distributions would appear to be much more difficult than writing the distribution code. |
|
Yes, I was thinking about that after your comment. A simple test could be to generate a lot of numbers, fill something like 256 buckets, and compare if they roughly follow the distribution. But that would only catch the worst errors. Shall I open an issue? |
As discussed in #68.
Benchmarks before (with
i128_support):After:
And the normal code with a one-time set-up cost for comparison:
The performance of
sample_singledepends quite a bit on how close the range is to a power of two, but I have not investigated the details... Performance seems worth the extra method.I am not sure the order of arguments is the best choice, with
(low, high, rng). Would(rng, low, high)be better?Also I tried to make
sample_singlehave a default implementation, like inRangeFloat, but couldn't get it to work.