Skip to content
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

StepRng almost always produces bool false #1303

Closed
jayvdb opened this issue Mar 23, 2023 · 4 comments · Fixed by #1304
Closed

StepRng almost always produces bool false #1303

jayvdb opened this issue Mar 23, 2023 · 4 comments · Fixed by #1304

Comments

@jayvdb
Copy link

jayvdb commented Mar 23, 2023

I was trying to use StepRng to produce bool true, and found that I much harder than expected.
i.e. the following assertion is almost always true.

for i in 0..usize::MAX as u64 {
    for j in [0, 1, i] {
        let mut rng = rand::rngs::mock::StepRng::new(i, j);
        for k in 0..1000 {
            let foo: bool = rng.gen();
            if foo {
                eprintln!("{i} {j} {k}");
            }

            assert!(!foo);
        }
    }
}

I was able to get a true when "i=2147484" "j=2147484" & "k=999".

(edit: it becomes true when the start is 4013646938112, and then is consistently true, for a while at least)

I guess based on response for #1248 that there isn't much love for StepRng, and maybe this is just an unfortunate effect of StepRng

My real motivation is looking for a solution to cksac/fake-rs#128. I am trying to build a generator that is reasonably random most of the time, except when asked to produce a bool, it should always produce true. Is this possible?

My crude guess was if I could eliminate 0 from the rng responses, this would eliminate generating false, and StepRng seemed like a useful way to experiment with this idea.

@jayvdb jayvdb changed the title StepRng always produces bool false StepRng almost always produces bool false Mar 23, 2023
@WarrenWeckesser
Copy link
Collaborator

The result will be true when bit 31 of the internal u64 counter is 1. For example, this will print all true values:

    let initial = 1u64 << 31;
    let increment = 0;
    let mut rng = rand::rngs::mock::StepRng::new(initial, increment);
    for _ in 0..8 {
        let foo: bool = rng.gen();
        println!("{}", foo);
    }

If you set initial to 0 and increment to 1u64 << 31, then each time the internal value is incremented, bit 31 changes, so this will print alternating false and true, starting with false:

    let initial = 0u64;
    let increment = 1u64 << 31;
    let mut rng = rand::rngs::mock::StepRng::new(initial, increment);
    for _ in 0..8 {
        let foo: bool = rng.gen();
        println!("{}", foo);
    }

@jayvdb
Copy link
Author

jayvdb commented Mar 23, 2023

Thank you! Perhaps it could be documented better? Not specifically explaining this scenario involving bools, but how using this struct relates to the internal logic of rand to produce values other than f64 (update: I should have wrote u64). Note I haven't read all of the Rust Rand Book , so maybe it is adequately explained elsewhere. Maybe all that is needed is a link on https://docs.rs/rand/latest/rand/rngs/mock/struct.StepRng.html with a note that types other than f64 behave in a non-intuitive fashion and "go read X to understand caveats for non-f64 (update: I should have wrote u64) usage".

Are there any other tools in the rand toolbox which can be used to produce random values, except always produce true for bools?

@dhardy
Copy link
Member

dhardy commented Mar 23, 2023

but how using this struct relates to the internal logic of rand to produce values other than f64

This RNG only directly implements next_u64 (and next_u32 as a cast). Everything else is implemented elsewhere, and value-stability rules mean the result won't change in a patch release but could in any other release.

In other words, by documenting this we might give users the false expectation that behaviour is stable. It's not (though in practice it won't change often).

@jayvdb
Copy link
Author

jayvdb commented Mar 23, 2023

What about a note something like

While this RNG does step by increment for signed & unsigned int data types, it may not step by that increment for other types, such as bool, float.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants