-
Notifications
You must be signed in to change notification settings - Fork 430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UniformInt::sample_single leading zeros approximation is biased #661
Comments
Well spotted. We could do with tests for this kind of thing but unfortunately I don't think it's practical. I think the error is here: let zone =
if ::core::$unsigned::MAX <= ::core::u16::MAX as $unsigned {
// Using a modulus is faster than the approximation for
// i8 and i16. I suppose we trade the cost of one
// modulus for near-perfect branch prediction.
let unsigned_max: $u_large = ::core::$u_large::MAX;
let ints_to_reject = (unsigned_max - range + 1) % range;
unsigned_max - ints_to_reject
} else {
// conservative but fast approximation
range << range.leading_zeros()
}; Here Instead we consider the upper-bound inclusive which avoids that problem, however this isn't compatible with the second case: there we should subtract 1 if the upper-bound is inclusive. However, what if (range << range.leading_zeros()).wrapping_sub(1) I think this is the best way of doing things since it avoids having to trap for special cases. Alternatively we could drop the It looks like this only affects Want to make a PR? |
Note that the bitmasking method has the same rejection probabilities as our leading zeros method: |
We could just do like I have and have tests for smaller integers. The logic is unlikely to change for larger integers. |
For every possible input, each possible output should be equally likely:
(playground link for verification: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=485be3f36a790b767a1d7366dd1de364)
I think all that's required is changing the comparison to
l < zone
The text was updated successfully, but these errors were encountered: