├── .github
├── FUNDING.yml
├── PULL_REQUEST_TEMPLATE.md
├── ISSUE_TEMPLATE
│ ├── other.md
│ ├── feature_request.md
│ ├── bug_report.md
│ ├── compile-issue.md
│ └── suggest-a-change.md
├── dependabot.yml
└── workflows
│ ├── benches.yml
│ └── test.yml
├── benches
├── rustfmt.toml
├── Cargo.toml
└── benches
│ ├── shuffle.rs
│ ├── standard.rs
│ ├── weighted.rs
│ ├── bool.rs
│ ├── simd.rs
│ ├── array.rs
│ ├── uniform_float.rs
│ ├── uniform.rs
│ ├── seq_choose.rs
│ └── generators.rs
├── utils
└── redirect.html
├── .gitignore
├── clippy.toml
├── examples
├── print-next.rs
├── monte-carlo.rs
├── rayon-monte-carlo.rs
└── monty-hall.rs
├── COPYRIGHT
├── rand_pcg
├── COPYRIGHT
├── Cargo.toml
├── LICENSE-MIT
├── README.md
├── tests
│ ├── lcg64xsh32.rs
│ ├── mcg128xsl64.rs
│ ├── lcg128xsl64.rs
│ └── lcg128cmdxsm64.rs
├── CHANGELOG.md
└── src
│ ├── lib.rs
│ ├── pcg64.rs
│ └── pcg128cm.rs
├── rand_chacha
├── COPYRIGHT
├── Cargo.toml
├── LICENSE-MIT
├── README.md
├── CHANGELOG.md
└── src
│ └── lib.rs
├── tests
└── fill.rs
├── LICENSE-MIT
├── src
├── prelude.rs
├── seq
│ ├── mod.rs
│ ├── increasing_uniform.rs
│ └── coin_flipper.rs
├── distr
│ ├── weighted
│ │ └── mod.rs
│ ├── slice.rs
│ ├── bernoulli.rs
│ ├── distribution.rs
│ └── mod.rs
└── rngs
│ ├── os.rs
│ ├── small.rs
│ ├── xoshiro128plusplus.rs
│ ├── xoshiro256plusplus.rs
│ ├── mod.rs
│ ├── thread.rs
│ └── reseeding.rs
├── Cargo.toml
├── SECURITY.md
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: dhardy
2 |
--------------------------------------------------------------------------------
/benches/rustfmt.toml:
--------------------------------------------------------------------------------
1 | max_width = 120
2 | fn_call_width = 108
3 |
--------------------------------------------------------------------------------
/utils/redirect.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target
2 | Cargo.lock
3 | rand_wasm_bindgen_test*.[tj]s
4 | rand_wasm_bindgen_test*.wasm
5 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | - [ ] Added a `CHANGELOG.md` entry
2 |
3 | # Summary
4 |
5 | # Motivation
6 |
7 | # Details
8 |
--------------------------------------------------------------------------------
/clippy.toml:
--------------------------------------------------------------------------------
1 | # Don't warn about these identifiers when using clippy::doc_markdown.
2 | doc-valid-idents = ["ChaCha", "ChaCha12", "SplitMix64", "ZiB", ".."]
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/other.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Other
3 | about: empty template
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/print-next.rs:
--------------------------------------------------------------------------------
1 | use rand::RngCore;
2 |
3 | fn main() {
4 | let mut rng = rand::rng();
5 | println!("Next u32: {0:>#18X} = {0:>20}", rng.next_u32());
6 | println!("Next u64: {0:>#18X} = {0:>20}", rng.next_u64());
7 | }
8 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "cargo"
4 | directory: "/"
5 | schedule:
6 | interval: "monthly"
7 | open-pull-requests-limit: 10
8 | - package-ecosystem: "github-actions"
9 | directory: "/"
10 | schedule:
11 | interval: "monthly"
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Background
11 |
12 | **What is your motivation?**
13 |
14 | **What type of application is this?** (E.g. cryptography, game, numerical simulation)
15 |
16 | ## Feature request
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Something doesn't work as expected
4 | title: ''
5 | labels: X-bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## Summary
11 |
12 | A clear and concise description of what the bug is.
13 |
14 | What behaviour is expected, and why?
15 |
16 | ## Code sample
17 |
18 | ```rust
19 | // Code demonstrating the problem
20 | ```
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/compile-issue.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Compile issue
3 | about: Report / ask about a compilation issue
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | # Common issues
11 |
12 | **Problem**: `rand_hc::Hc128Rng: rand_core::SeedableRng` (or other RNG)
13 |
14 | **Quick solution**: `cargo update`
15 |
16 | **Details**: This happens when multiple versions of the `rand_core` crate are in use. Check your `Cargo.lock` file for all versions of `rand_core`. Note that some versions (0.2.2 and 0.3.1) are compatibility shims and are not a problem by themselves.
17 |
--------------------------------------------------------------------------------
/COPYRIGHT:
--------------------------------------------------------------------------------
1 | Copyrights in the Rand project are retained by their contributors. No
2 | copyright assignment is required to contribute to the Rand project.
3 |
4 | For full authorship information, see the version control history.
5 |
6 | Except as otherwise noted (below and/or in individual files), Rand is
7 | licensed under the Apache License, Version 2.0 or
8 | or the MIT license
9 | or , at your option.
10 |
11 | The Rand project includes code from the Rust project
12 | published under these same licenses.
13 |
--------------------------------------------------------------------------------
/rand_pcg/COPYRIGHT:
--------------------------------------------------------------------------------
1 | Copyrights in the Rand project are retained by their contributors. No
2 | copyright assignment is required to contribute to the Rand project.
3 |
4 | For full authorship information, see the version control history.
5 |
6 | Except as otherwise noted (below and/or in individual files), Rand is
7 | licensed under the Apache License, Version 2.0 or
8 | or the MIT license
9 | or , at your option.
10 |
11 | The Rand project includes code from the Rust project
12 | published under these same licenses.
13 |
--------------------------------------------------------------------------------
/rand_chacha/COPYRIGHT:
--------------------------------------------------------------------------------
1 | Copyrights in the Rand project are retained by their contributors. No
2 | copyright assignment is required to contribute to the Rand project.
3 |
4 | For full authorship information, see the version control history.
5 |
6 | Except as otherwise noted (below and/or in individual files), Rand is
7 | licensed under the Apache License, Version 2.0 or
8 | or the MIT license
9 | or , at your option.
10 |
11 | The Rand project includes code from the Rust project
12 | published under these same licenses.
13 |
--------------------------------------------------------------------------------
/tests/fill.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2025 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | #![allow(unused)]
10 |
11 | use rand::{Fill, Rng};
12 |
13 | // Test that Fill may be implemented for externally-defined types
14 | struct MyInt(i32);
15 | impl Fill for MyInt {
16 | fn fill_slice(this: &mut [Self], rng: &mut R) {
17 | todo!()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/suggest-a-change.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Suggest a change
3 | about: Describe this issue template's purpose here.
4 | title: 'CHANGE: '
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | A change request is considered a (small) Request-For-Comment, and requires a concrete proposal and motivation.
11 |
12 | ## Summary
13 |
14 | How does this affect the API / end-user? (Include API-breaking changes, value-breaking changes and API additions.)
15 |
16 | ## Details
17 |
18 | What changes does this require internally?
19 |
20 | ## Motivation
21 |
22 | What is the motivation for this change?
23 |
24 | Since every change has a cost (even if just API churn or extra code size), every change must have sufficient motivation. This is arguably the most important part of the RFC.
25 |
26 | ## Alternatives
27 |
28 | Which alternatives might be considered, and why or why not?
29 |
--------------------------------------------------------------------------------
/rand_pcg/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rand_pcg"
3 | version = "0.10.0-rc.1"
4 | authors = ["The Rand Project Developers"]
5 | license = "MIT OR Apache-2.0"
6 | readme = "README.md"
7 | repository = "https://github.com/rust-random/rand"
8 | documentation = "https://docs.rs/rand_pcg"
9 | homepage = "https://rust-random.github.io/book"
10 | description = """
11 | Selected PCG random number generators
12 | """
13 | keywords = ["random", "rng", "pcg"]
14 | categories = ["algorithms", "no-std"]
15 | edition = "2024"
16 | rust-version = "1.85"
17 |
18 | [package.metadata.docs.rs]
19 | all-features = true
20 | rustdoc-args = ["--generate-link-to-definition"]
21 |
22 | [features]
23 | serde = ["dep:serde"]
24 |
25 | [dependencies]
26 | rand_core = { version = "0.10.0-rc-2" }
27 | serde = { version = "1", features = ["derive"], optional = true }
28 |
29 | [dev-dependencies]
30 | # This is for testing serde, unfortunately we can't specify feature-gated dev
31 | # deps yet, see: https://github.com/rust-lang/cargo/issues/1596
32 | postcard = {version = "1.1.3", default-features = false, features = ["alloc"]}
33 |
--------------------------------------------------------------------------------
/.github/workflows/benches.yml:
--------------------------------------------------------------------------------
1 | name: Benches
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | paths-ignore:
7 | - "**.md"
8 | - "examples/**"
9 | pull_request:
10 | branches: [ master ]
11 | paths-ignore:
12 | - "**.md"
13 | - "examples/**"
14 |
15 | defaults:
16 | run:
17 | working-directory: ./benches
18 |
19 | jobs:
20 | clippy-fmt:
21 | name: "Benches: Check Clippy and rustfmt"
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/checkout@v4
25 | - uses: dtolnay/rust-toolchain@master
26 | with:
27 | toolchain: stable
28 | components: clippy, rustfmt
29 | - name: Rustfmt
30 | run: cargo fmt -- --check
31 | - name: Clippy
32 | run: cargo clippy --all-targets -- -D warnings
33 | benches:
34 | name: "Benches: Test"
35 | runs-on: ubuntu-latest
36 | steps:
37 | - uses: actions/checkout@v4
38 | - uses: dtolnay/rust-toolchain@master
39 | with:
40 | toolchain: nightly
41 | - name: Test
42 | run: RUSTFLAGS=-Dwarnings cargo test --benches
43 |
--------------------------------------------------------------------------------
/benches/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "benches"
3 | version = "0.1.0"
4 | edition = "2024"
5 | publish = false
6 |
7 | [features]
8 | # Option (requires nightly Rust): experimental SIMD support
9 | simd_support = ["rand/simd_support"]
10 |
11 | [dependencies]
12 |
13 | [dev-dependencies]
14 | rand = { path = "..", features = ["small_rng", "nightly"] }
15 | rand_pcg = { path = "../rand_pcg" }
16 | rand_chacha = { path = "../rand_chacha" }
17 | criterion = "0.5"
18 | criterion-cycles-per-byte = "0.6"
19 |
20 | [[bench]]
21 | name = "array"
22 | harness = false
23 |
24 | [[bench]]
25 | name = "bool"
26 | harness = false
27 |
28 | [[bench]]
29 | name = "generators"
30 | harness = false
31 |
32 | [[bench]]
33 | name = "seq_choose"
34 | harness = false
35 |
36 | [[bench]]
37 | name = "shuffle"
38 | harness = false
39 |
40 | [[bench]]
41 | name = "simd"
42 | harness = false
43 |
44 | [[bench]]
45 | name = "standard"
46 | harness = false
47 |
48 | [[bench]]
49 | name = "uniform"
50 | harness = false
51 |
52 | [[bench]]
53 | name = "uniform_float"
54 | harness = false
55 |
56 | [[bench]]
57 | name = "weighted"
58 | harness = false
59 |
--------------------------------------------------------------------------------
/rand_chacha/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rand_chacha"
3 | version = "0.10.0-rc.1"
4 | authors = ["The Rand Project Developers", "The Rust Project Developers", "The CryptoCorrosion Contributors"]
5 | license = "MIT OR Apache-2.0"
6 | readme = "README.md"
7 | repository = "https://github.com/rust-random/rand"
8 | documentation = "https://docs.rs/rand_chacha"
9 | homepage = "https://rust-random.github.io/book"
10 | description = """
11 | ChaCha random number generator
12 | """
13 | keywords = ["random", "rng", "chacha"]
14 | categories = ["algorithms", "no-std"]
15 | edition = "2024"
16 | rust-version = "1.85"
17 |
18 | [package.metadata.docs.rs]
19 | all-features = true
20 | rustdoc-args = ["--generate-link-to-definition"]
21 |
22 | [dependencies]
23 | rand_core = { version = "0.10.0-rc-2" }
24 | ppv-lite86 = { version = "0.2.14", default-features = false, features = ["simd"] }
25 | serde = { version = "1.0", features = ["derive"], optional = true }
26 |
27 | [dev-dependencies]
28 | # Only to test serde
29 | serde_json = "1.0.120"
30 | rand = { path = "..", version = "0.10.0-rc.0" }
31 |
32 | [features]
33 | default = ["std"]
34 | std = ["ppv-lite86/std"]
35 | serde = ["dep:serde"]
36 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright 2018 Developers of the Rand project
2 | Copyright (c) 2014 The Rust Project Developers
3 |
4 | Permission is hereby granted, free of charge, to any
5 | person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the
7 | Software without restriction, including without
8 | limitation the rights to use, copy, modify, merge,
9 | publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software
11 | is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice
15 | shall be included in all copies or substantial portions
16 | of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | DEALINGS IN THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/rand_chacha/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright 2018 Developers of the Rand project
2 | Copyright (c) 2014 The Rust Project Developers
3 |
4 | Permission is hereby granted, free of charge, to any
5 | person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the
7 | Software without restriction, including without
8 | limitation the rights to use, copy, modify, merge,
9 | publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software
11 | is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice
15 | shall be included in all copies or substantial portions
16 | of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | DEALINGS IN THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/rand_pcg/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
2 | Copyright 2018 Developers of the Rand project
3 |
4 | Permission is hereby granted, free of charge, to any
5 | person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the
7 | Software without restriction, including without
8 | limitation the rights to use, copy, modify, merge,
9 | publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software
11 | is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice
15 | shall be included in all copies or substantial portions
16 | of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | DEALINGS IN THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/src/prelude.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Convenience re-export of common members
10 | //!
11 | //! Like the standard library's prelude, this module simplifies importing of
12 | //! common items. Unlike the standard prelude, the contents of this module must
13 | //! be imported manually:
14 | //!
15 | //! ```
16 | //! use rand::prelude::*;
17 | //! # let mut r = StdRng::from_rng(&mut rand::rng());
18 | //! # let _: f32 = r.random();
19 | //! ```
20 |
21 | #[doc(no_inline)]
22 | pub use crate::distr::Distribution;
23 | #[cfg(feature = "small_rng")]
24 | #[doc(no_inline)]
25 | pub use crate::rngs::SmallRng;
26 | #[cfg(feature = "std_rng")]
27 | #[doc(no_inline)]
28 | pub use crate::rngs::StdRng;
29 | #[doc(no_inline)]
30 | #[cfg(feature = "thread_rng")]
31 | pub use crate::rngs::ThreadRng;
32 | #[doc(no_inline)]
33 | pub use crate::seq::{IndexedMutRandom, IndexedRandom, IteratorRandom, SliceRandom};
34 | #[doc(no_inline)]
35 | pub use crate::{CryptoRng, Rng, RngCore, SeedableRng};
36 |
--------------------------------------------------------------------------------
/rand_pcg/README.md:
--------------------------------------------------------------------------------
1 | # rand_pcg
2 |
3 | [](https://github.com/rust-random/rand/actions)
4 | [](https://crates.io/crates/rand_pcg)
5 | [](https://rust-random.github.io/book/)
6 | [](https://docs.rs/rand_pcg)
7 |
8 | Implements a selection of PCG random number generators.
9 |
10 | > PCG is a family of simple fast space-efficient statistically good algorithms
11 | > for random number generation. [Melissa O'Neill, Harvey Mudd College, 2014].
12 |
13 | The PCG algorithms are not suitable for cryptographic uses, but perform well
14 | in statistical tests, use little memory and are fairly fast.
15 | See the [pcg-random website](http://www.pcg-random.org/).
16 |
17 | This crate depends on [rand_core](https://crates.io/crates/rand_core) and is
18 | part of the [Rand project](https://github.com/rust-random/rand).
19 |
20 | Links:
21 |
22 | - [API documentation (docs.rs)](https://docs.rs/rand_pcg)
23 | - [Changelog](https://github.com/rust-random/rand/blob/master/rand_pcg/CHANGELOG.md)
24 |
25 |
26 | ## Crate Features
27 |
28 | `rand_pcg` is `no_std` compatible by default.
29 |
30 | The `serde` feature includes implementations of `Serialize` and `Deserialize`
31 | for the included RNGs.
32 |
33 | ## License
34 |
35 | `rand_pcg` is distributed under the terms of both the MIT license and the
36 | Apache License (Version 2.0).
37 |
38 | See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
39 | [COPYRIGHT](COPYRIGHT) for details.
40 |
--------------------------------------------------------------------------------
/examples/monte-carlo.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | // Copyright 2013-2018 The Rust Project Developers.
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | //! # Monte Carlo estimation of π
11 | //!
12 | //! Imagine that we have a square with sides of length 2 and a unit circle
13 | //! (radius = 1), both centered at the origin. The areas are:
14 | //!
15 | //! ```text
16 | //! area of circle = πr² = π * r * r = π
17 | //! area of square = 2² = 4
18 | //! ```
19 | //!
20 | //! The circle is entirely within the square, so if we sample many points
21 | //! randomly from the square, roughly π / 4 of them should be inside the circle.
22 | //!
23 | //! We can use the above fact to estimate the value of π: pick many points in
24 | //! the square at random, calculate the fraction that fall within the circle,
25 | //! and multiply this fraction by 4.
26 | use rand::distr::{Distribution, Uniform};
27 |
28 | fn main() {
29 | let range = Uniform::new(-1.0f64, 1.0).unwrap();
30 | let mut rng = rand::rng();
31 |
32 | let total = 1_000_000;
33 | let mut in_circle = 0;
34 |
35 | for _ in 0..total {
36 | let a = range.sample(&mut rng);
37 | let b = range.sample(&mut rng);
38 | if a * a + b * b <= 1.0 {
39 | in_circle += 1;
40 | }
41 | }
42 |
43 | // prints something close to 3.14159...
44 | println!(
45 | "π is approximately {}",
46 | 4. * (in_circle as f64) / (total as f64)
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/rand_chacha/README.md:
--------------------------------------------------------------------------------
1 | # rand_chacha
2 |
3 | [](https://github.com/rust-random/rand/actions)
4 | [](https://crates.io/crates/rand_chacha)
5 | [](https://rust-random.github.io/book/)
6 | [](https://docs.rs/rand_chacha)
7 |
8 | A cryptographically secure random number generator that uses the ChaCha
9 | algorithm.
10 |
11 | ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use
12 | as an RNG. It is an improved variant of the Salsa20 cipher family, which was
13 | selected as one of the "stream ciphers suitable for widespread adoption" by
14 | eSTREAM[^2].
15 |
16 | The RNGs provided by this crate are implemented via the fast stream ciphers of
17 | the [`c2-chacha`](https://crates.io/crates/c2-chacha) crate.
18 |
19 | Links:
20 |
21 | - [API documentation (docs.rs)](https://docs.rs/rand_chacha)
22 | - [Changelog](https://github.com/rust-random/rand/blob/master/rand_chacha/CHANGELOG.md)
23 |
24 | [rand]: https://crates.io/crates/rand
25 | [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*](
26 | https://cr.yp.to/chacha.html)
27 |
28 | [^2]: [eSTREAM: the ECRYPT Stream Cipher Project](
29 | http://www.ecrypt.eu.org/stream/)
30 |
31 |
32 | ## Crate Features
33 |
34 | `rand_chacha` is `no_std` compatible when disabling default features; the `std`
35 | feature can be explicitly required to re-enable `std` support. Using `std`
36 | allows detection of CPU features and thus better optimisation.
37 |
38 |
39 | # License
40 |
41 | `rand_chacha` is distributed under the terms of both the MIT license and the
42 | Apache License (Version 2.0).
43 |
44 | See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT), and
45 | [COPYRIGHT](COPYRIGHT) for details.
46 |
--------------------------------------------------------------------------------
/rand_pcg/tests/lcg64xsh32.rs:
--------------------------------------------------------------------------------
1 | use rand_core::{RngCore, SeedableRng};
2 | use rand_pcg::{Lcg64Xsh32, Pcg32};
3 |
4 | #[test]
5 | fn test_lcg64xsh32_advancing() {
6 | for seed in 0..20 {
7 | let mut rng1 = Lcg64Xsh32::seed_from_u64(seed);
8 | let mut rng2 = rng1.clone();
9 | for _ in 0..20 {
10 | rng1.next_u32();
11 | }
12 | rng2.advance(20);
13 | assert_eq!(rng1, rng2);
14 | }
15 | }
16 |
17 | #[test]
18 | fn test_lcg64xsh32_construction() {
19 | // Test that various construction techniques produce a working RNG.
20 | let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
21 | let mut rng1 = Lcg64Xsh32::from_seed(seed);
22 | assert_eq!(rng1.next_u64(), 1204678643940597513);
23 |
24 | let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1);
25 | assert_eq!(rng2.next_u64(), 12384929573776311845);
26 |
27 | let mut rng3 = Lcg64Xsh32::seed_from_u64(0);
28 | assert_eq!(rng3.next_u64(), 18195738587432868099);
29 |
30 | // This is the same as Lcg64Xsh32, so we only have a single test:
31 | let mut rng4 = Pcg32::seed_from_u64(0);
32 | assert_eq!(rng4.next_u64(), 18195738587432868099);
33 | }
34 |
35 | #[test]
36 | fn test_lcg64xsh32_reference() {
37 | // Numbers copied from official test suite.
38 | let mut rng = Lcg64Xsh32::new(42, 54);
39 |
40 | let mut results = [0u32; 6];
41 | for i in results.iter_mut() {
42 | *i = rng.next_u32();
43 | }
44 | let expected: [u32; 6] = [
45 | 0xa15c02b7, 0x7b47f409, 0xba1d3330, 0x83d2f293, 0xbfa4784b, 0xcbed606e,
46 | ];
47 | assert_eq!(results, expected);
48 | }
49 |
50 | #[cfg(feature = "serde")]
51 | #[test]
52 | fn test_lcg64xsh32_serde() {
53 | use postcard;
54 | let mut rng = Lcg64Xsh32::seed_from_u64(0);
55 |
56 | let buf = postcard::to_allocvec(&rng).expect("Could not serialize");
57 |
58 | let mut deserialized: Lcg64Xsh32 = postcard::from_bytes(&buf).expect("Could not deserialize");
59 |
60 | for _ in 0..16 {
61 | assert_eq!(rng.next_u64(), deserialized.next_u64());
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/rand_pcg/tests/mcg128xsl64.rs:
--------------------------------------------------------------------------------
1 | use rand_core::{RngCore, SeedableRng};
2 | use rand_pcg::{Mcg128Xsl64, Pcg64Mcg};
3 |
4 | #[test]
5 | fn test_mcg128xsl64_advancing() {
6 | for seed in 0..20 {
7 | let mut rng1 = Mcg128Xsl64::seed_from_u64(seed);
8 | let mut rng2 = rng1.clone();
9 | for _ in 0..20 {
10 | rng1.next_u64();
11 | }
12 | rng2.advance(20);
13 | assert_eq!(rng1, rng2);
14 | }
15 | }
16 |
17 | #[test]
18 | fn test_mcg128xsl64_construction() {
19 | // Test that various construction techniques produce a working RNG.
20 | let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
21 | let mut rng1 = Mcg128Xsl64::from_seed(seed);
22 | assert_eq!(rng1.next_u64(), 7071994460355047496);
23 |
24 | let mut rng2 = Mcg128Xsl64::from_rng(&mut rng1);
25 | assert_eq!(rng2.next_u64(), 12300796107712034932);
26 |
27 | let mut rng3 = Mcg128Xsl64::seed_from_u64(0);
28 | assert_eq!(rng3.next_u64(), 6198063878555692194);
29 |
30 | // This is the same as Mcg128Xsl64, so we only have a single test:
31 | let mut rng4 = Pcg64Mcg::seed_from_u64(0);
32 | assert_eq!(rng4.next_u64(), 6198063878555692194);
33 | }
34 |
35 | #[test]
36 | fn test_mcg128xsl64_reference() {
37 | // Numbers copied from official test suite (C version).
38 | let mut rng = Mcg128Xsl64::new(42);
39 |
40 | let mut results = [0u64; 6];
41 | for i in results.iter_mut() {
42 | *i = rng.next_u64();
43 | }
44 | let expected: [u64; 6] = [
45 | 0x63b4a3a813ce700a,
46 | 0x382954200617ab24,
47 | 0xa7fd85ae3fe950ce,
48 | 0xd715286aa2887737,
49 | 0x60c92fee2e59f32c,
50 | 0x84c4e96beff30017,
51 | ];
52 | assert_eq!(results, expected);
53 | }
54 |
55 | #[cfg(feature = "serde")]
56 | #[test]
57 | fn test_mcg128xsl64_serde() {
58 | use postcard;
59 |
60 | let mut rng = Mcg128Xsl64::seed_from_u64(0);
61 |
62 | let buf = postcard::to_allocvec(&rng).expect("Could not serialize");
63 |
64 | let mut deserialized: Mcg128Xsl64 = postcard::from_bytes(&buf).expect("Could not deserialize");
65 |
66 | for _ in 0..16 {
67 | assert_eq!(rng.next_u64(), deserialized.next_u64());
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/benches/benches/shuffle.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use criterion::{Criterion, black_box, criterion_group, criterion_main};
10 | use rand::SeedableRng;
11 | use rand::prelude::*;
12 | use rand_pcg::Pcg32;
13 |
14 | criterion_group!(
15 | name = benches;
16 | config = Criterion::default();
17 | targets = bench
18 | );
19 | criterion_main!(benches);
20 |
21 | pub fn bench(c: &mut Criterion) {
22 | c.bench_function("seq_shuffle_100", |b| {
23 | let mut rng = Pcg32::from_rng(&mut rand::rng());
24 | let mut buf = [0i32; 100];
25 | rng.fill(&mut buf);
26 | let x = black_box(&mut buf);
27 | b.iter(|| {
28 | x.shuffle(&mut rng);
29 | x[0]
30 | })
31 | });
32 |
33 | bench_rng::(c, "ChaCha12");
34 | bench_rng::(c, "Pcg32");
35 | bench_rng::(c, "Pcg64");
36 | }
37 |
38 | fn bench_rng(c: &mut Criterion, rng_name: &'static str) {
39 | for length in [1, 2, 3, 10, 100, 1000, 10000].map(black_box) {
40 | c.bench_function(format!("shuffle_{length}_{rng_name}").as_str(), |b| {
41 | let mut rng = Rng::seed_from_u64(123);
42 | let mut vec: Vec = (0..length).collect();
43 | b.iter(|| {
44 | vec.shuffle(&mut rng);
45 | vec[0]
46 | })
47 | });
48 |
49 | if length >= 10 {
50 | let name = format!("partial_shuffle_{length}_{rng_name}");
51 | c.bench_function(name.as_str(), |b| {
52 | let mut rng = Rng::seed_from_u64(123);
53 | let mut vec: Vec = (0..length).collect();
54 | b.iter(|| {
55 | vec.partial_shuffle(&mut rng, length / 2);
56 | vec[0]
57 | })
58 | });
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/benches/benches/standard.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use core::time::Duration;
10 | use criterion::measurement::WallTime;
11 | use criterion::{BenchmarkGroup, Criterion, criterion_group, criterion_main};
12 | use rand::distr::{Alphabetic, Alphanumeric, Open01, OpenClosed01, StandardUniform};
13 | use rand::prelude::*;
14 | use rand_pcg::Pcg64Mcg;
15 |
16 | criterion_group!(
17 | name = benches;
18 | config = Criterion::default();
19 | targets = bench
20 | );
21 | criterion_main!(benches);
22 |
23 | fn bench_ty(g: &mut BenchmarkGroup, name: &str)
24 | where
25 | D: Distribution + Default,
26 | {
27 | g.throughput(criterion::Throughput::Bytes(core::mem::size_of::() as u64));
28 | g.bench_function(name, |b| {
29 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
30 |
31 | b.iter(|| rng.sample::(D::default()));
32 | });
33 | }
34 |
35 | pub fn bench(c: &mut Criterion) {
36 | let mut g = c.benchmark_group("StandardUniform");
37 | g.sample_size(1000);
38 | g.warm_up_time(Duration::from_millis(500));
39 | g.measurement_time(Duration::from_millis(1000));
40 |
41 | macro_rules! do_ty {
42 | ($t:ty) => {
43 | bench_ty::<$t, StandardUniform>(&mut g, stringify!($t));
44 | };
45 | ($t:ty, $($tt:ty),*) => {
46 | do_ty!($t);
47 | do_ty!($($tt),*);
48 | };
49 | }
50 |
51 | do_ty!(i8, i16, i32, i64, i128);
52 | do_ty!(f32, f64);
53 | do_ty!(char);
54 |
55 | bench_ty::(&mut g, "Alphabetic");
56 | bench_ty::(&mut g, "Alphanumeric");
57 |
58 | bench_ty::(&mut g, "Open01/f32");
59 | bench_ty::(&mut g, "Open01/f64");
60 | bench_ty::(&mut g, "OpenClosed01/f32");
61 | bench_ty::(&mut g, "OpenClosed01/f64");
62 |
63 | g.finish();
64 | }
65 |
--------------------------------------------------------------------------------
/rand_pcg/tests/lcg128xsl64.rs:
--------------------------------------------------------------------------------
1 | use rand_core::{RngCore, SeedableRng};
2 | use rand_pcg::{Lcg128Xsl64, Pcg64};
3 |
4 | #[test]
5 | fn test_lcg128xsl64_advancing() {
6 | for seed in 0..20 {
7 | let mut rng1 = Lcg128Xsl64::seed_from_u64(seed);
8 | let mut rng2 = rng1.clone();
9 | for _ in 0..20 {
10 | rng1.next_u64();
11 | }
12 | rng2.advance(20);
13 | assert_eq!(rng1, rng2);
14 | }
15 | }
16 |
17 | #[test]
18 | fn test_lcg128xsl64_construction() {
19 | // Test that various construction techniques produce a working RNG.
20 | #[rustfmt::skip]
21 | let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16,
22 | 17,18,19,20, 21,22,23,24, 25,26,27,28, 29,30,31,32];
23 | let mut rng1 = Lcg128Xsl64::from_seed(seed);
24 | assert_eq!(rng1.next_u64(), 8740028313290271629);
25 |
26 | let mut rng2 = Lcg128Xsl64::from_rng(&mut rng1);
27 | assert_eq!(rng2.next_u64(), 1922280315005786345);
28 |
29 | let mut rng3 = Lcg128Xsl64::seed_from_u64(0);
30 | assert_eq!(rng3.next_u64(), 2354861276966075475);
31 |
32 | // This is the same as Lcg128Xsl64, so we only have a single test:
33 | let mut rng4 = Pcg64::seed_from_u64(0);
34 | assert_eq!(rng4.next_u64(), 2354861276966075475);
35 | }
36 |
37 | #[test]
38 | fn test_lcg128xsl64_reference() {
39 | // Numbers copied from official test suite (C version).
40 | let mut rng = Lcg128Xsl64::new(42, 54);
41 |
42 | let mut results = [0u64; 6];
43 | for i in results.iter_mut() {
44 | *i = rng.next_u64();
45 | }
46 | let expected: [u64; 6] = [
47 | 0x86b1da1d72062b68,
48 | 0x1304aa46c9853d39,
49 | 0xa3670e9e0dd50358,
50 | 0xf9090e529a7dae00,
51 | 0xc85b9fd837996f2c,
52 | 0x606121f8e3919196,
53 | ];
54 | assert_eq!(results, expected);
55 | }
56 |
57 | #[cfg(feature = "serde")]
58 | #[test]
59 | fn test_lcg128xsl64_serde() {
60 | use postcard;
61 |
62 | let mut rng = Lcg128Xsl64::seed_from_u64(0);
63 |
64 | let buf = postcard::to_allocvec(&rng).expect("Could not serialize");
65 |
66 | let mut deserialized: Lcg128Xsl64 = postcard::from_bytes(&buf).expect("Could not deserialize");
67 |
68 | for _ in 0..16 {
69 | assert_eq!(rng.next_u64(), deserialized.next_u64());
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/benches/benches/weighted.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use criterion::{Criterion, black_box, criterion_group, criterion_main};
10 | use rand::distr::weighted::WeightedIndex;
11 | use rand::prelude::*;
12 | use rand::seq::index::sample_weighted;
13 |
14 | criterion_group!(
15 | name = benches;
16 | config = Criterion::default();
17 | targets = bench
18 | );
19 | criterion_main!(benches);
20 |
21 | pub fn bench(c: &mut Criterion) {
22 | c.bench_function("weighted_index_creation", |b| {
23 | let mut rng = rand::rng();
24 | let weights = black_box([1u32, 2, 4, 0, 5, 1, 7, 1, 2, 3, 4, 5, 6, 7]);
25 | b.iter(|| {
26 | let distr = WeightedIndex::new(weights.to_vec()).unwrap();
27 | rng.sample(distr)
28 | })
29 | });
30 |
31 | c.bench_function("weighted_index_modification", |b| {
32 | let mut rng = rand::rng();
33 | let weights = black_box([1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7]);
34 | let mut distr = WeightedIndex::new(weights.to_vec()).unwrap();
35 | b.iter(|| {
36 | distr.update_weights(&[(2, &4), (5, &1)]).unwrap();
37 | rng.sample(&distr)
38 | })
39 | });
40 |
41 | let lens = [
42 | (1, 1000, "1k"),
43 | (10, 1000, "1k"),
44 | (100, 1000, "1k"),
45 | (100, 1_000_000, "1M"),
46 | (200, 1_000_000, "1M"),
47 | (400, 1_000_000, "1M"),
48 | (600, 1_000_000, "1M"),
49 | (1000, 1_000_000, "1M"),
50 | ];
51 | for (amount, length, len_name) in lens {
52 | let name = format!("weighted_sample_indices_{amount}_of_{len_name}");
53 | c.bench_function(name.as_str(), |b| {
54 | let length = black_box(length);
55 | let amount = black_box(amount);
56 | let mut rng = SmallRng::from_rng(&mut rand::rng());
57 | b.iter(|| sample_weighted(&mut rng, length, |idx| (1 + (idx % 100)) as u32, amount))
58 | });
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/rand_pcg/tests/lcg128cmdxsm64.rs:
--------------------------------------------------------------------------------
1 | use rand_core::{RngCore, SeedableRng};
2 | use rand_pcg::{Lcg128CmDxsm64, Pcg64Dxsm};
3 |
4 | #[test]
5 | fn test_lcg128cmdxsm64_advancing() {
6 | for seed in 0..20 {
7 | let mut rng1 = Lcg128CmDxsm64::seed_from_u64(seed);
8 | let mut rng2 = rng1.clone();
9 | for _ in 0..20 {
10 | rng1.next_u64();
11 | }
12 | rng2.advance(20);
13 | assert_eq!(rng1, rng2);
14 | }
15 | }
16 |
17 | #[test]
18 | fn test_lcg128cmdxsm64_construction() {
19 | // Test that various construction techniques produce a working RNG.
20 | #[rustfmt::skip]
21 | let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16,
22 | 17,18,19,20, 21,22,23,24, 25,26,27,28, 29,30,31,32];
23 | let mut rng1 = Lcg128CmDxsm64::from_seed(seed);
24 | assert_eq!(rng1.next_u64(), 12201417210360370199);
25 |
26 | let mut rng2 = Lcg128CmDxsm64::from_rng(&mut rng1);
27 | assert_eq!(rng2.next_u64(), 11487972556150888383);
28 |
29 | let mut rng3 = Lcg128CmDxsm64::seed_from_u64(0);
30 | assert_eq!(rng3.next_u64(), 4111470453933123814);
31 |
32 | // This is the same as Lcg128CmDxsm64, so we only have a single test:
33 | let mut rng4 = Pcg64Dxsm::seed_from_u64(0);
34 | assert_eq!(rng4.next_u64(), 4111470453933123814);
35 | }
36 |
37 | #[test]
38 | fn test_lcg128cmdxsm64_reference() {
39 | // Numbers determined using `pcg_engines::cm_setseq_dxsm_128_64` from pcg-cpp.
40 | let mut rng = Lcg128CmDxsm64::new(42, 54);
41 |
42 | let mut results = [0u64; 6];
43 | for i in results.iter_mut() {
44 | *i = rng.next_u64();
45 | }
46 | let expected: [u64; 6] = [
47 | 17331114245835578256,
48 | 10267467544499227306,
49 | 9726600296081716989,
50 | 10165951391103677450,
51 | 12131334649314727261,
52 | 10134094537930450875,
53 | ];
54 | assert_eq!(results, expected);
55 | }
56 |
57 | #[cfg(feature = "serde")]
58 | #[test]
59 | fn test_lcg128cmdxsm64_serde() {
60 | use postcard;
61 |
62 | let mut rng = Lcg128CmDxsm64::seed_from_u64(0);
63 |
64 | let buf = postcard::to_allocvec(&rng).expect("Could not serialize");
65 |
66 | let mut deserialized: Lcg128CmDxsm64 =
67 | postcard::from_bytes(&buf).expect("Could not deserialize");
68 |
69 | for _ in 0..16 {
70 | assert_eq!(rng.next_u64(), deserialized.next_u64());
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/benches/benches/bool.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Generating/filling arrays and iterators of output
10 |
11 | use criterion::{Criterion, criterion_group, criterion_main};
12 | use rand::distr::Bernoulli;
13 | use rand::prelude::*;
14 | use rand_pcg::Pcg32;
15 |
16 | criterion_group!(
17 | name = benches;
18 | config = Criterion::default();
19 | targets = bench
20 | );
21 | criterion_main!(benches);
22 |
23 | pub fn bench(c: &mut Criterion) {
24 | let mut g = c.benchmark_group("random_bool");
25 | g.sample_size(1000);
26 | g.warm_up_time(core::time::Duration::from_millis(500));
27 | g.measurement_time(core::time::Duration::from_millis(1000));
28 |
29 | g.bench_function("standard", |b| {
30 | let mut rng = Pcg32::from_rng(&mut rand::rng());
31 | b.iter(|| rng.sample::(rand::distr::StandardUniform))
32 | });
33 |
34 | g.bench_function("const", |b| {
35 | let mut rng = Pcg32::from_rng(&mut rand::rng());
36 | b.iter(|| rng.random_bool(0.18))
37 | });
38 |
39 | g.bench_function("var", |b| {
40 | let mut rng = Pcg32::from_rng(&mut rand::rng());
41 | let p = rng.random();
42 | b.iter(|| rng.random_bool(p))
43 | });
44 |
45 | g.bench_function("ratio_const", |b| {
46 | let mut rng = Pcg32::from_rng(&mut rand::rng());
47 | b.iter(|| rng.random_ratio(2, 3))
48 | });
49 |
50 | g.bench_function("ratio_var", |b| {
51 | let mut rng = Pcg32::from_rng(&mut rand::rng());
52 | let d = rng.random_range(1..=100);
53 | let n = rng.random_range(0..=d);
54 | b.iter(|| rng.random_ratio(n, d));
55 | });
56 |
57 | g.bench_function("bernoulli_const", |b| {
58 | let mut rng = Pcg32::from_rng(&mut rand::rng());
59 | let d = Bernoulli::new(0.18).unwrap();
60 | b.iter(|| rng.sample(d))
61 | });
62 |
63 | g.bench_function("bernoulli_var", |b| {
64 | let mut rng = Pcg32::from_rng(&mut rand::rng());
65 | let p = rng.random();
66 | let d = Bernoulli::new(p).unwrap();
67 | b.iter(|| rng.sample(d))
68 | });
69 | }
70 |
--------------------------------------------------------------------------------
/benches/benches/simd.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Generating SIMD / wide types
10 |
11 | #![cfg_attr(feature = "simd_support", feature(portable_simd))]
12 |
13 | use criterion::{Criterion, criterion_group, criterion_main};
14 |
15 | criterion_group!(
16 | name = benches;
17 | config = Criterion::default();
18 | targets = simd
19 | );
20 | criterion_main!(benches);
21 |
22 | #[cfg(not(feature = "simd_support"))]
23 | pub fn simd(_: &mut Criterion) {}
24 |
25 | #[cfg(feature = "simd_support")]
26 | pub fn simd(c: &mut Criterion) {
27 | use rand::prelude::*;
28 | use rand_pcg::Pcg64Mcg;
29 |
30 | let mut g = c.benchmark_group("random_simd");
31 |
32 | g.bench_function("u128", |b| {
33 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
34 | b.iter(|| rng.random::());
35 | });
36 |
37 | g.bench_function("m128i", |b| {
38 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
39 | b.iter(|| rng.random::());
40 | });
41 |
42 | g.bench_function("m256i", |b| {
43 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
44 | b.iter(|| rng.random::());
45 | });
46 |
47 | g.bench_function("m512i", |b| {
48 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
49 | b.iter(|| rng.random::());
50 | });
51 |
52 | g.bench_function("u64x2", |b| {
53 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
54 | b.iter(|| rng.random::());
55 | });
56 |
57 | g.bench_function("u32x4", |b| {
58 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
59 | b.iter(|| rng.random::());
60 | });
61 |
62 | g.bench_function("u32x8", |b| {
63 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
64 | b.iter(|| rng.random::());
65 | });
66 |
67 | g.bench_function("u16x8", |b| {
68 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
69 | b.iter(|| rng.random::());
70 | });
71 |
72 | g.bench_function("u8x16", |b| {
73 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
74 | b.iter(|| rng.random::());
75 | });
76 | }
77 |
--------------------------------------------------------------------------------
/rand_pcg/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 | ## [Unreleased]
8 | ### Changes
9 | - Use Edition 2024 and MSRV 1.85 (#1653)
10 | - Remove feature `os_rng` (#1674)
11 | - Use `postcard` instead of `bincode` to test the serde feature (#1693)
12 |
13 | ## [0.9.0] - 2025-01-27
14 | ### Dependencies and features
15 | - Update to `rand_core` v0.9.0 (#1558)
16 | - Rename feature `serde1` to `serde` (#1477)
17 | - Rename feature `getrandom` to `os_rng` (#1537)
18 |
19 | ### Other changes
20 | - Add `Lcg128CmDxsm64` generator compatible with NumPy's `PCG64DXSM` (#1202)
21 | - Add examples for initializing the RNGs (#1352)
22 | - Revise crate docs (#1454)
23 |
24 | ## [0.3.1] - 2021-06-15
25 | - Add `advance` methods to RNGs (#1111)
26 | - Document dependencies between streams (#1122)
27 |
28 | ## [0.3.0] - 2020-12-08
29 | - Bump `rand_core` version to 0.6.0
30 | - Bump MSRV to 1.36 (#1011)
31 | - Derive PartialEq+Eq for Lcg64Xsh32, Lcg128Xsl64, and Mcg128Xsl64 (#979)
32 |
33 | ## [0.2.1] - 2019-10-22
34 | - Bump `bincode` version to 1.1.4 to fix minimal-dependency builds
35 | - Removed unused `autocfg` build dependency.
36 |
37 | ## [0.2.0] - 2019-06-12
38 | - Add `Lcg128Xsl64` aka `Pcg64`
39 | - Bump minor crate version since rand_core bump is a breaking change
40 | - Switch to Edition 2018
41 |
42 | ## [0.1.2] - 2019-02-23
43 | - require `bincode` 1.1.2 for i128 auto-detection
44 | - make `bincode` a dev-dependency again #663
45 | - clean up tests and Serde support
46 |
47 | ## [0.1.1] - 2018-10-04
48 | - make `bincode` an explicit dependency when using Serde
49 |
50 | ## [0.1.0] - 2018-10-04
51 | Initial release, including:
52 |
53 | - `Lcg64Xsh32` aka `Pcg32`
54 | - `Mcg128Xsl64` aka `Pcg64Mcg`
55 |
56 | [Unreleased]: https://github.com/rust-random/rand/compare/0.9.0...HEAD
57 | [0.9.0]: https://github.com/rust-random/rand/compare/rand_pcg-0.3.1...0.9.0
58 | [0.3.1]: https://github.com/rust-random/rand/compare/rand_pcg-0.3.0...rand_pcg-0.3.1
59 | [0.3.0]: https://github.com/rust-random/rand/compare/rand_pcg-0.2.1...rand_pcg-0.3.0
60 | [0.2.1]: https://github.com/rust-random/rand/compare/rand_pcg-0.2.0...rand_pcg-0.2.1
61 | [0.2.0]: https://github.com/rust-random/rand/compare/rand_pcg-0.1.2...rand_pcg-0.2.0
62 | [0.1.2]: https://github.com/rust-random/rand/compare/6d9e7ac9c6980897d190ede70607f18501d99f3b...rand_pcg-0.1.2
63 | [0.1.1]: https://github.com/rust-random/small-rngs/compare/rand_pcg-0.1.0...rand_pcg-0.1.1
64 | [0.1.0]: https://github.com/rust-random/small-rngs/compare/8ae22ced3f1cfdb888e639f93ca24ef1ea5811c2...rand_pcg-0.1.0
65 |
--------------------------------------------------------------------------------
/rand_chacha/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 | ## [Unreleased]
8 | ### Changed
9 | - Bump MSRV to 1.85 and edition to 2024 (#1671)
10 | - Remove feature `os_rng` (#1674)
11 |
12 | ## [0.9.0] - 2025-01-27
13 | ### Dependencies and features
14 | - Update to `rand_core` v0.9.0 (#1558)
15 | - Feature `std` now implies feature `rand_core/std` (#1153)
16 | - Rename feature `serde1` to `serde` (#1477)
17 | - Rename feature `getrandom` to `os_rng` (#1537)
18 |
19 | ### Other changes
20 | - Remove usage of `unsafe` in `fn generate` (#1181) then optimise for AVX2 (~4-7%) (#1192)
21 | - Revise crate docs (#1454)
22 |
23 | ## [0.3.1] - 2021-06-09
24 | - add getters corresponding to existing setters: `get_seed`, `get_stream` (#1124)
25 | - add serde support, gated by the `serde1` feature (#1124)
26 | - ensure expected layout via `repr(transparent)` (#1120)
27 |
28 | ## [0.3.0] - 2020-12-08
29 | - Bump `rand_core` version to 0.6.0
30 | - Bump MSRV to 1.36 (#1011)
31 | - Remove usage of deprecated feature "simd" of `ppv-lite86` (#979), then revert
32 | this change (#1023) since SIMD is only enabled by default from `ppv-lite86 v0.2.10`
33 | - impl PartialEq+Eq for ChaChaXRng and ChaChaXCore (#979)
34 | - Fix panic on block counter wrap that was occurring in debug builds (#980)
35 |
36 | ## [0.2.2] - 2020-03-09
37 | - Integrate `c2-chacha`, reducing dependency count (#931)
38 | - Add CryptoRng to ChaChaXCore (#944)
39 |
40 | ## [0.2.1] - 2019-07-22
41 | - Force enable the `simd` feature of `c2-chacha` (#845)
42 |
43 | ## [0.2.0] - 2019-06-06
44 | - Rewrite based on the much faster `c2-chacha` crate (#789)
45 |
46 | ## [0.1.1] - 2019-01-04
47 | - Disable `i128` and `u128` if the `target_os` is `emscripten` (#671: work-around Emscripten limitation)
48 | - Update readme and doc links
49 |
50 | ## [0.1.0] - 2018-10-17
51 | - Pulled out of the Rand crate
52 |
53 | [Unreleased]: https://github.com/rust-random/rand/compare/0.9.0...HEAD
54 | [0.9.0]: https://github.com/rust-random/rand/compare/rand_chacha-0.3.1...0.9.0
55 | [0.3.1]: https://github.com/rust-random/rand/compare/rand_chacha-0.3.0...rand_chacha-0.3.1
56 | [0.3.0]: https://github.com/rust-random/rand/compare/rand_chacha-0.2.2...rand_chacha-0.3.0
57 | [0.2.2]: https://github.com/rust-random/rand/compare/rand_chacha-0.2.1...rand_chacha-0.2.2
58 | [0.2.1]: https://github.com/rust-random/rand/compare/rand_chacha-0.2.0...rand_chacha-0.2.1
59 | [0.2.0]: https://github.com/rust-random/rand/compare/rand_chacha-0.1.1...rand_chacha-0.2.0
60 | [0.1.1]: https://github.com/rust-random/rand/compare/rand_chacha-0.1.0...rand_chacha-0.1.1
61 | [0.1.0]: https://github.com/rust-random/rand/compare/a55ba3feb49062ea8dec75c034d796f6e3f763ae...rand_chacha-0.1.0
62 |
--------------------------------------------------------------------------------
/src/seq/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Sequence-related functionality
10 | //!
11 | //! This module provides:
12 | //!
13 | //! * [`IndexedRandom`] for sampling slices and other indexable lists
14 | //! * [`IndexedMutRandom`] for sampling slices and other mutably indexable lists
15 | //! * [`SliceRandom`] for mutating slices
16 | //! * [`IteratorRandom`] for sampling iterators
17 | //! * [`index::sample`] low-level API to choose multiple indices from
18 | //! `0..length`
19 | //!
20 | //! Also see:
21 | //!
22 | //! * [`crate::distr::weighted::WeightedIndex`] distribution which provides
23 | //! weighted index sampling.
24 | //!
25 | //! In order to make results reproducible across 32-64 bit architectures, all
26 | //! `usize` indices are sampled as a `u32` where possible (also providing a
27 | //! small performance boost in some cases).
28 |
29 | mod coin_flipper;
30 | mod increasing_uniform;
31 | mod iterator;
32 | mod slice;
33 |
34 | #[cfg(feature = "alloc")]
35 | #[path = "index.rs"]
36 | mod index_;
37 |
38 | #[cfg(feature = "alloc")]
39 | #[doc(no_inline)]
40 | pub use crate::distr::weighted::Error as WeightError;
41 | pub use iterator::IteratorRandom;
42 | #[cfg(feature = "alloc")]
43 | pub use slice::IndexedSamples;
44 | #[allow(deprecated)]
45 | #[cfg(feature = "alloc")]
46 | pub use slice::SliceChooseIter;
47 | pub use slice::{IndexedMutRandom, IndexedRandom, SliceRandom};
48 |
49 | /// Low-level API for sampling indices
50 | pub mod index {
51 | use crate::Rng;
52 |
53 | #[cfg(feature = "alloc")]
54 | #[doc(inline)]
55 | pub use super::index_::*;
56 |
57 | /// Randomly sample exactly `N` distinct indices from `0..len`, and
58 | /// return them in random order (fully shuffled).
59 | ///
60 | /// This is implemented via Floyd's algorithm. Time complexity is `O(N^2)`
61 | /// and memory complexity is `O(N)`.
62 | ///
63 | /// Returns `None` if (and only if) `N > len`.
64 | pub fn sample_array(rng: &mut R, len: usize) -> Option<[usize; N]>
65 | where
66 | R: Rng + ?Sized,
67 | {
68 | if N > len {
69 | return None;
70 | }
71 |
72 | // Floyd's algorithm
73 | let mut indices = [0; N];
74 | for (i, j) in (len - N..len).enumerate() {
75 | let t = rng.random_range(..j + 1);
76 | if let Some(pos) = indices[0..i].iter().position(|&x| x == t) {
77 | indices[pos] = j;
78 | }
79 | indices[i] = t;
80 | }
81 | Some(indices)
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rand"
3 | version = "0.10.0-rc.5"
4 | authors = ["The Rand Project Developers", "The Rust Project Developers"]
5 | license = "MIT OR Apache-2.0"
6 | readme = "README.md"
7 | repository = "https://github.com/rust-random/rand"
8 | documentation = "https://docs.rs/rand"
9 | homepage = "https://rust-random.github.io/book"
10 | description = """
11 | Random number generators and other randomness functionality.
12 | """
13 | keywords = ["random", "rng"]
14 | categories = ["algorithms", "no-std"]
15 | autobenches = true
16 | edition = "2024"
17 | rust-version = "1.85"
18 | include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"]
19 |
20 | [package.metadata.docs.rs]
21 | # To build locally:
22 | # RUSTDOCFLAGS="--cfg docsrs -Zunstable-options --generate-link-to-definition" cargo +nightly doc --all --all-features --no-deps --open
23 | all-features = true
24 | rustdoc-args = ["--generate-link-to-definition"]
25 |
26 | [package.metadata.playground]
27 | features = ["small_rng", "serde"]
28 |
29 | [features]
30 | # Meta-features:
31 | default = ["std", "std_rng", "os_rng", "small_rng", "thread_rng"]
32 | nightly = [] # some additions requiring nightly Rust
33 | serde = ["dep:serde"]
34 |
35 | # Option (enabled by default): without "std" rand uses libcore; this option
36 | # enables functionality expected to be available on a standard platform.
37 | std = ["alloc", "getrandom?/std"]
38 |
39 | # Option: "alloc" enables support for Vec and Box when not using "std"
40 | alloc = []
41 |
42 | # Option: enable OsRng
43 | os_rng = ["dep:getrandom"]
44 |
45 | # Option (requires nightly Rust): experimental SIMD support
46 | simd_support = []
47 |
48 | # Option (enabled by default): enable StdRng
49 | std_rng = ["dep:chacha20"]
50 |
51 | # Option: enable SmallRng
52 | small_rng = []
53 |
54 | # Option: enable ThreadRng and rng()
55 | thread_rng = ["std", "std_rng", "os_rng"]
56 |
57 | # Option: enable rand::rngs::ChaCha*Rng
58 | chacha = ["dep:chacha20"]
59 |
60 | # Option: use unbiased sampling for algorithms supporting this option: Uniform distribution.
61 | # By default, bias affecting no more than one in 2^48 samples is accepted.
62 | # Note: enabling this option is expected to affect reproducibility of results.
63 | unbiased = []
64 |
65 | # Option: enable logging
66 | log = ["dep:log"]
67 |
68 | [workspace]
69 | members = [
70 | "rand_chacha",
71 | "rand_pcg",
72 | ]
73 | exclude = ["benches", "distr_test"]
74 |
75 | [dependencies]
76 | rand_core = { version = "0.10.0-rc-2", default-features = false }
77 | log = { version = "0.4.4", optional = true }
78 | serde = { version = "1.0.103", features = ["derive"], optional = true }
79 | chacha20 = { version = "=0.10.0-rc.5", default-features = false, features = ["rng"], optional = true }
80 | getrandom = { version = "0.3.0", optional = true }
81 |
82 | [dev-dependencies]
83 | rand_pcg = { path = "rand_pcg", version = "0.10.0-rc.1" }
84 | # Only to test serde
85 | postcard = {version = "1.1.3", default-features = false, features = ["alloc"]}
86 | rayon = "1.7"
87 | serde_json = "1.0.140"
88 |
--------------------------------------------------------------------------------
/benches/benches/array.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Generating/filling arrays and iterators of output
10 |
11 | use criterion::{Criterion, criterion_group, criterion_main};
12 | use rand::distr::StandardUniform;
13 | use rand::prelude::*;
14 | use rand_pcg::Pcg64Mcg;
15 |
16 | criterion_group!(
17 | name = benches;
18 | config = Criterion::default();
19 | targets = bench
20 | );
21 | criterion_main!(benches);
22 |
23 | pub fn bench(c: &mut Criterion) {
24 | let mut g = c.benchmark_group("random_1kb");
25 | g.throughput(criterion::Throughput::Bytes(1024));
26 |
27 | g.bench_function("u16_iter_repeat", |b| {
28 | use core::iter;
29 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
30 | b.iter(|| {
31 | let v: Vec = iter::repeat(()).map(|()| rng.random()).take(512).collect();
32 | v
33 | });
34 | });
35 |
36 | g.bench_function("u16_sample_iter", |b| {
37 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
38 | b.iter(|| {
39 | let v: Vec = StandardUniform.sample_iter(&mut rng).take(512).collect();
40 | v
41 | });
42 | });
43 |
44 | g.bench_function("u16_gen_array", |b| {
45 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
46 | b.iter(|| {
47 | let v: [u16; 512] = rng.random();
48 | v
49 | });
50 | });
51 |
52 | g.bench_function("u16_fill", |b| {
53 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
54 | let mut buf = [0u16; 512];
55 | b.iter(|| {
56 | rng.fill(&mut buf[..]);
57 | buf
58 | });
59 | });
60 |
61 | g.bench_function("u64_iter_repeat", |b| {
62 | use core::iter;
63 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
64 | b.iter(|| {
65 | let v: Vec = iter::repeat(()).map(|()| rng.random()).take(128).collect();
66 | v
67 | });
68 | });
69 |
70 | g.bench_function("u64_sample_iter", |b| {
71 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
72 | b.iter(|| {
73 | let v: Vec = StandardUniform.sample_iter(&mut rng).take(128).collect();
74 | v
75 | });
76 | });
77 |
78 | g.bench_function("u64_gen_array", |b| {
79 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
80 | b.iter(|| {
81 | let v: [u64; 128] = rng.random();
82 | v
83 | });
84 | });
85 |
86 | g.bench_function("u64_fill", |b| {
87 | let mut rng = Pcg64Mcg::from_rng(&mut rand::rng());
88 | let mut buf = [0u64; 128];
89 | b.iter(|| {
90 | rng.fill(&mut buf[..]);
91 | buf
92 | });
93 | });
94 | }
95 |
--------------------------------------------------------------------------------
/examples/rayon-monte-carlo.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | // Copyright 2013-2018 The Rust Project Developers.
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | //! # Monte Carlo estimation of π with a chosen seed and rayon for parallelism
11 | //!
12 | //! Imagine that we have a square with sides of length 2 and a unit circle
13 | //! (radius = 1), both centered at the origin. The areas are:
14 | //!
15 | //! ```text
16 | //! area of circle = πr² = π * r * r = π
17 | //! area of square = 2² = 4
18 | //! ```
19 | //!
20 | //! The circle is entirely within the square, so if we sample many points
21 | //! randomly from the square, roughly π / 4 of them should be inside the circle.
22 | //!
23 | //! We can use the above fact to estimate the value of π: pick many points in
24 | //! the square at random, calculate the fraction that fall within the circle,
25 | //! and multiply this fraction by 4.
26 | //!
27 | //! Note on determinism:
28 | //! It's slightly tricky to build a parallel simulation using Rayon
29 | //! which is both efficient *and* reproducible.
30 | //!
31 | //! Rayon's ParallelIterator api does not guarantee that the work will be
32 | //! batched into identical batches on every run, so we can't simply use
33 | //! map_init to construct one RNG per Rayon batch.
34 | //!
35 | //! Instead, we do our own batching, so that a Rayon work item becomes a
36 | //! batch. Then we can fix our rng stream to the batched work item.
37 | //! Batching amortizes the cost of constructing the Rng from a fixed seed
38 | //! over BATCH_SIZE trials. Manually batching also turns out to be faster
39 | //! for the nondeterministic version of this program as well.
40 |
41 | use chacha20::ChaCha8Rng;
42 | use rand::distr::{Distribution, Uniform};
43 | use rand_core::SeedableRng;
44 | use rayon::prelude::*;
45 |
46 | static SEED: u64 = 0;
47 | static BATCH_SIZE: u64 = 10_000;
48 | static BATCHES: u64 = 1000;
49 |
50 | fn main() {
51 | let range = Uniform::new(-1.0f64, 1.0).unwrap();
52 |
53 | let in_circle = (0..BATCHES)
54 | .into_par_iter()
55 | .map(|i| {
56 | let mut rng = ChaCha8Rng::seed_from_u64(SEED);
57 | // We chose ChaCha because it's fast, has suitable statistical properties for simulation,
58 | // and because it supports this set_stream() api, which lets us choose a different stream
59 | // per work item. ChaCha supports 2^64 independent streams.
60 | rng.set_stream(i);
61 | let mut count = 0;
62 | for _ in 0..BATCH_SIZE {
63 | let a = range.sample(&mut rng);
64 | let b = range.sample(&mut rng);
65 | if a * a + b * b <= 1.0 {
66 | count += 1;
67 | }
68 | }
69 | count
70 | })
71 | .sum::();
72 |
73 | // assert this is deterministic
74 | assert_eq!(in_circle, 7852263);
75 |
76 | // prints something close to 3.14159...
77 | println!(
78 | "π is approximately {}",
79 | 4. * (in_circle as f64) / ((BATCH_SIZE * BATCHES) as f64)
80 | );
81 | }
82 |
--------------------------------------------------------------------------------
/benches/benches/uniform_float.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Implement benchmarks for uniform distributions over FP types
10 | //!
11 | //! Sampling methods compared:
12 | //!
13 | //! - sample: current method: (x12 - 1.0) * (b - a) + a
14 |
15 | use core::time::Duration;
16 | use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
17 | use rand::distr::uniform::{SampleUniform, Uniform, UniformSampler};
18 | use rand::prelude::*;
19 | use rand_chacha::ChaCha8Rng;
20 | use rand_pcg::{Pcg32, Pcg64};
21 |
22 | const WARM_UP_TIME: Duration = Duration::from_millis(1000);
23 | const MEASUREMENT_TIME: Duration = Duration::from_secs(3);
24 | const SAMPLE_SIZE: usize = 100_000;
25 | const N_RESAMPLES: usize = 10_000;
26 |
27 | macro_rules! single_random {
28 | ($R:ty, $T:ty, $g:expr) => {
29 | $g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| {
30 | let mut rng = <$R>::from_rng(&mut rand::rng());
31 | let (mut low, mut high);
32 | loop {
33 | low = <$T>::from_bits(rng.random());
34 | high = <$T>::from_bits(rng.random());
35 | if (low < high) && (high - low).is_normal() {
36 | break;
37 | }
38 | }
39 |
40 | b.iter(|| <$T as SampleUniform>::Sampler::sample_single_inclusive(low, high, &mut rng));
41 | });
42 | };
43 |
44 | ($c:expr, $T:ty) => {{
45 | let mut g = $c.benchmark_group("uniform_single");
46 | g.sample_size(SAMPLE_SIZE);
47 | g.warm_up_time(WARM_UP_TIME);
48 | g.measurement_time(MEASUREMENT_TIME);
49 | g.nresamples(N_RESAMPLES);
50 | single_random!(SmallRng, $T, g);
51 | single_random!(ChaCha8Rng, $T, g);
52 | single_random!(Pcg32, $T, g);
53 | single_random!(Pcg64, $T, g);
54 | g.finish();
55 | }};
56 | }
57 |
58 | fn single_random(c: &mut Criterion) {
59 | single_random!(c, f32);
60 | single_random!(c, f64);
61 | }
62 |
63 | macro_rules! distr_random {
64 | ($R:ty, $T:ty, $g:expr) => {
65 | $g.bench_function(BenchmarkId::new(stringify!($T), stringify!($R)), |b| {
66 | let mut rng = <$R>::from_rng(&mut rand::rng());
67 | let dist = loop {
68 | let low = <$T>::from_bits(rng.random());
69 | let high = <$T>::from_bits(rng.random());
70 | if let Ok(dist) = Uniform::<$T>::new_inclusive(low, high) {
71 | break dist;
72 | }
73 | };
74 |
75 | b.iter(|| dist.sample(&mut rng));
76 | });
77 | };
78 |
79 | ($c:expr, $T:ty) => {{
80 | let mut g = $c.benchmark_group("uniform_distribution");
81 | g.sample_size(SAMPLE_SIZE);
82 | g.warm_up_time(WARM_UP_TIME);
83 | g.measurement_time(MEASUREMENT_TIME);
84 | g.nresamples(N_RESAMPLES);
85 | distr_random!(SmallRng, $T, g);
86 | distr_random!(ChaCha8Rng, $T, g);
87 | distr_random!(Pcg32, $T, g);
88 | distr_random!(Pcg64, $T, g);
89 | g.finish();
90 | }};
91 | }
92 |
93 | fn distr_random(c: &mut Criterion) {
94 | distr_random!(c, f32);
95 | distr_random!(c, f64);
96 | }
97 |
98 | criterion_group! {
99 | name = benches;
100 | config = Criterion::default();
101 | targets = single_random, distr_random
102 | }
103 | criterion_main!(benches);
104 |
--------------------------------------------------------------------------------
/src/seq/increasing_uniform.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use crate::{Rng, RngCore};
10 |
11 | /// Similar to a Uniform distribution,
12 | /// but after returning a number in the range [0,n], n is increased by 1.
13 | pub(crate) struct IncreasingUniform {
14 | pub rng: R,
15 | n: u32,
16 | // Chunk is a random number in [0, (n + 1) * (n + 2) *..* (n + chunk_remaining) )
17 | chunk: u32,
18 | chunk_remaining: u8,
19 | }
20 |
21 | impl IncreasingUniform {
22 | /// Create a dice roller.
23 | /// The next item returned will be a random number in the range [0,n]
24 | pub fn new(rng: R, n: u32) -> Self {
25 | // If n = 0, the first number returned will always be 0
26 | // so we don't need to generate a random number
27 | let chunk_remaining = if n == 0 { 1 } else { 0 };
28 | Self {
29 | rng,
30 | n,
31 | chunk: 0,
32 | chunk_remaining,
33 | }
34 | }
35 |
36 | /// Returns a number in [0,n] and increments n by 1.
37 | /// Generates new random bits as needed
38 | /// Panics if `n >= u32::MAX`
39 | #[inline]
40 | pub fn next_index(&mut self) -> usize {
41 | let next_n = self.n + 1;
42 |
43 | // There's room for further optimisation here:
44 | // random_range uses rejection sampling (or other method; see #1196) to avoid bias.
45 | // When the initial sample is biased for range 0..bound
46 | // it may still be viable to use for a smaller bound
47 | // (especially if small biases are considered acceptable).
48 |
49 | let next_chunk_remaining = self.chunk_remaining.checked_sub(1).unwrap_or_else(|| {
50 | // If the chunk is empty, generate a new chunk
51 | let (bound, remaining) = calculate_bound_u32(next_n);
52 | // bound = (n + 1) * (n + 2) *..* (n + remaining)
53 | self.chunk = self.rng.random_range(..bound);
54 | // Chunk is a random number in
55 | // [0, (n + 1) * (n + 2) *..* (n + remaining) )
56 |
57 | remaining - 1
58 | });
59 |
60 | let result = if next_chunk_remaining == 0 {
61 | // `chunk` is a random number in the range [0..n+1)
62 | // Because `chunk_remaining` is about to be set to zero
63 | // we do not need to clear the chunk here
64 | self.chunk as usize
65 | } else {
66 | // `chunk` is a random number in a range that is a multiple of n+1
67 | // so r will be a random number in [0..n+1)
68 | let r = self.chunk % next_n;
69 | self.chunk /= next_n;
70 | r as usize
71 | };
72 |
73 | self.chunk_remaining = next_chunk_remaining;
74 | self.n = next_n;
75 | result
76 | }
77 | }
78 |
79 | #[inline]
80 | /// Calculates `bound`, `count` such that bound (m)*(m+1)*..*(m + remaining - 1)
81 | fn calculate_bound_u32(m: u32) -> (u32, u8) {
82 | debug_assert!(m > 0);
83 | #[inline]
84 | const fn inner(m: u32) -> (u32, u8) {
85 | let mut product = m;
86 | let mut current = m + 1;
87 |
88 | loop {
89 | if let Some(p) = u32::checked_mul(product, current) {
90 | product = p;
91 | current += 1;
92 | } else {
93 | // Count has a maximum value of 13 for when min is 1 or 2
94 | let count = (current - m) as u8;
95 | return (product, count);
96 | }
97 | }
98 | }
99 |
100 | const RESULT2: (u32, u8) = inner(2);
101 | if m == 2 {
102 | // Making this value a constant instead of recalculating it
103 | // gives a significant (~50%) performance boost for small shuffles
104 | return RESULT2;
105 | }
106 |
107 | inner(m)
108 | }
109 |
--------------------------------------------------------------------------------
/src/distr/weighted/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Weighted (index) sampling
10 | //!
11 | //! Primarily, this module houses the [`WeightedIndex`] distribution.
12 | //! See also [`rand_distr::weighted`] for alternative implementations supporting
13 | //! potentially-faster sampling or a more easily modifiable tree structure.
14 | //!
15 | //! [`rand_distr::weighted`]: https://docs.rs/rand_distr/latest/rand_distr/weighted/index.html
16 |
17 | use core::fmt;
18 | mod weighted_index;
19 |
20 | pub use weighted_index::WeightedIndex;
21 |
22 | /// Bounds on a weight
23 | ///
24 | /// See usage in [`WeightedIndex`].
25 | pub trait Weight: Clone {
26 | /// Representation of 0
27 | const ZERO: Self;
28 |
29 | /// Checked addition
30 | ///
31 | /// - `Result::Ok`: On success, `v` is added to `self`
32 | /// - `Result::Err`: Returns an error when `Self` cannot represent the
33 | /// result of `self + v` (i.e. overflow). The value of `self` should be
34 | /// discarded.
35 | #[allow(clippy::result_unit_err)]
36 | fn checked_add_assign(&mut self, v: &Self) -> Result<(), ()>;
37 | }
38 |
39 | macro_rules! impl_weight_int {
40 | ($t:ty) => {
41 | impl Weight for $t {
42 | const ZERO: Self = 0;
43 | fn checked_add_assign(&mut self, v: &Self) -> Result<(), ()> {
44 | match self.checked_add(*v) {
45 | Some(sum) => {
46 | *self = sum;
47 | Ok(())
48 | }
49 | None => Err(()),
50 | }
51 | }
52 | }
53 | };
54 | ($t:ty, $($tt:ty),*) => {
55 | impl_weight_int!($t);
56 | impl_weight_int!($($tt),*);
57 | }
58 | }
59 | impl_weight_int!(i8, i16, i32, i64, i128, isize);
60 | impl_weight_int!(u8, u16, u32, u64, u128, usize);
61 |
62 | macro_rules! impl_weight_float {
63 | ($t:ty) => {
64 | impl Weight for $t {
65 | const ZERO: Self = 0.0;
66 |
67 | fn checked_add_assign(&mut self, v: &Self) -> Result<(), ()> {
68 | // Floats have an explicit representation for overflow
69 | *self += *v;
70 | Ok(())
71 | }
72 | }
73 | };
74 | }
75 | impl_weight_float!(f32);
76 | impl_weight_float!(f64);
77 |
78 | /// Invalid weight errors
79 | ///
80 | /// This type represents errors from [`WeightedIndex::new`],
81 | /// [`WeightedIndex::update_weights`] and other weighted distributions.
82 | #[derive(Debug, Clone, Copy, PartialEq, Eq)]
83 | // Marked non_exhaustive to allow a new error code in the solution to #1476.
84 | #[non_exhaustive]
85 | pub enum Error {
86 | /// The input weight sequence is empty, too long, or wrongly ordered
87 | InvalidInput,
88 |
89 | /// A weight is negative, too large for the distribution, or not a valid number
90 | InvalidWeight,
91 |
92 | /// Not enough non-zero weights are available to sample values
93 | ///
94 | /// When attempting to sample a single value this implies that all weights
95 | /// are zero. When attempting to sample `amount` values this implies that
96 | /// less than `amount` weights are greater than zero.
97 | InsufficientNonZero,
98 |
99 | /// Overflow when calculating the sum of weights
100 | Overflow,
101 | }
102 |
103 | #[cfg(feature = "std")]
104 | impl std::error::Error for Error {}
105 |
106 | impl fmt::Display for Error {
107 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 | f.write_str(match *self {
109 | Error::InvalidInput => "Weights sequence is empty/too long/unordered",
110 | Error::InvalidWeight => "A weight is negative, too large or not a valid number",
111 | Error::InsufficientNonZero => "Not enough weights > zero",
112 | Error::Overflow => "Overflow when summing weights",
113 | })
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/rand_pcg/src/lib.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! The PCG random number generators.
10 | //!
11 | //! This is a native Rust implementation of a small selection of [PCG generators].
12 | //! The primary goal of this crate is simple, minimal, well-tested code; in
13 | //! other words it is explicitly not a goal to re-implement all of PCG.
14 | //!
15 | //! ## Generators
16 | //!
17 | //! This crate provides:
18 | //!
19 | //! - [`Pcg32`] aka [`Lcg64Xsh32`], officially known as `pcg32`, a general
20 | //! purpose RNG. This is a good choice on both 32-bit and 64-bit CPUs
21 | //! (for 32-bit output).
22 | //! - [`Pcg64`] aka [`Lcg128Xsl64`], officially known as `pcg64`, a general
23 | //! purpose RNG. This is a good choice on 64-bit CPUs.
24 | //! - [`Pcg64Mcg`] aka [`Mcg128Xsl64`], officially known as `pcg64_fast`,
25 | //! a general purpose RNG using 128-bit multiplications. This has poor
26 | //! performance on 32-bit CPUs but is a good choice on 64-bit CPUs for
27 | //! both 32-bit and 64-bit output.
28 | //!
29 | //! These generators are all deterministic and portable (see [Reproducibility]
30 | //! in the book), with testing against reference vectors.
31 | //!
32 | //! ## Seeding (construction)
33 | //!
34 | //! Generators implement the [`SeedableRng`] trait. All methods are suitable for
35 | //! seeding. Some suggestions:
36 | //!
37 | //! 1. To automatically seed with a unique seed, use [`SeedableRng::from_rng`]
38 | //! with a master generator (here [`rand::rng()`](https://docs.rs/rand/latest/rand/fn.rng.html)):
39 | //! ```ignore
40 | //! use rand_core::SeedableRng;
41 | //! use rand_pcg::Pcg64Mcg;
42 | //! let rng = Pcg64Mcg::from_rng(&mut rand::rng());
43 | //! # let _: Pcg64Mcg = rng;
44 | //! ```
45 | //! 2. Seed **from an integer** via `seed_from_u64`. This uses a hash function
46 | //! internally to yield a (typically) good seed from any input.
47 | //! ```
48 | //! # use {rand_core::SeedableRng, rand_pcg::Pcg64Mcg};
49 | //! let rng = Pcg64Mcg::seed_from_u64(1);
50 | //! # let _: Pcg64Mcg = rng;
51 | //! ```
52 | //!
53 | //! See also [Seeding RNGs] in the book.
54 | //!
55 | //! ## Generation
56 | //!
57 | //! Generators implement [`RngCore`], whose methods may be used directly to
58 | //! generate unbounded integer or byte values.
59 | //! ```
60 | //! use rand_core::{SeedableRng, RngCore};
61 | //! use rand_pcg::Pcg64Mcg;
62 | //!
63 | //! let mut rng = Pcg64Mcg::seed_from_u64(0);
64 | //! let x = rng.next_u64();
65 | //! assert_eq!(x, 0x5603f242407deca2);
66 | //! ```
67 | //!
68 | //! It is often more convenient to use the [`rand::Rng`] trait, which provides
69 | //! further functionality. See also the [Random Values] chapter in the book.
70 | //!
71 | //! [PCG generators]: https://www.pcg-random.org/
72 | //! [Reproducibility]: https://rust-random.github.io/book/crate-reprod.html
73 | //! [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html
74 | //! [Random Values]: https://rust-random.github.io/book/guide-values.html
75 | //! [`RngCore`]: rand_core::RngCore
76 | //! [`SeedableRng`]: rand_core::SeedableRng
77 | //! [`SeedableRng::from_rng`]: rand_core::SeedableRng#method.from_rng
78 | //! [`rand::rng`]: https://docs.rs/rand/latest/rand/fn.rng.html
79 | //! [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html
80 | //! [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html
81 |
82 | #![doc(
83 | html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
84 | html_favicon_url = "https://www.rust-lang.org/favicon.ico"
85 | )]
86 | #![forbid(unsafe_code)]
87 | #![deny(missing_docs)]
88 | #![deny(missing_debug_implementations)]
89 | #![no_std]
90 |
91 | mod pcg128;
92 | mod pcg128cm;
93 | mod pcg64;
94 |
95 | pub use rand_core;
96 |
97 | pub use self::pcg64::{Lcg64Xsh32, Pcg32};
98 | pub use self::pcg128::{Lcg128Xsl64, Mcg128Xsl64, Pcg64, Pcg64Mcg};
99 | pub use self::pcg128cm::{Lcg128CmDxsm64, Pcg64Dxsm};
100 |
--------------------------------------------------------------------------------
/src/rngs/os.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Interface to the random number generator of the operating system.
10 |
11 | use crate::{TryCryptoRng, TryRngCore};
12 |
13 | /// An interface over the operating-system's random data source
14 | ///
15 | /// This is a zero-sized struct. It can be freely constructed with just `OsRng`.
16 | ///
17 | /// The implementation is provided by the [getrandom] crate. Refer to
18 | /// [getrandom] documentation for details.
19 | ///
20 | /// This struct is available as `rand_core::OsRng` and as `rand::rngs::OsRng`.
21 | /// In both cases, this requires the crate feature `os_rng` or `std`
22 | /// (enabled by default in `rand` but not in `rand_core`).
23 | ///
24 | /// # Blocking and error handling
25 | ///
26 | /// It is possible that when used during early boot the first call to `OsRng`
27 | /// will block until the system's RNG is initialised. It is also possible
28 | /// (though highly unlikely) for `OsRng` to fail on some platforms, most
29 | /// likely due to system mis-configuration.
30 | ///
31 | /// After the first successful call, it is highly unlikely that failures or
32 | /// significant delays will occur (although performance should be expected to
33 | /// be much slower than a user-space
34 | /// [PRNG](https://rust-random.github.io/book/guide-gen.html#pseudo-random-number-generators)).
35 | ///
36 | /// # Usage example
37 | /// ```
38 | /// use rand::{TryRngCore, rngs::OsRng};
39 | ///
40 | /// let mut key = [0u8; 16];
41 | /// OsRng.try_fill_bytes(&mut key).unwrap();
42 | /// let random_u64 = OsRng.try_next_u64().unwrap();
43 | /// ```
44 | ///
45 | /// [getrandom]: https://crates.io/crates/getrandom
46 | #[derive(Clone, Copy, Debug, Default)]
47 | pub struct OsRng;
48 |
49 | /// Error type of [`OsRng`]
50 | #[derive(Clone, Copy, Debug, PartialEq, Eq)]
51 | pub struct OsError(getrandom::Error);
52 |
53 | impl core::fmt::Display for OsError {
54 | #[inline]
55 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
56 | self.0.fmt(f)
57 | }
58 | }
59 |
60 | // NOTE: this can use core::error::Error from rustc 1.81.0
61 | #[cfg(feature = "std")]
62 | impl std::error::Error for OsError {
63 | #[inline]
64 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
65 | std::error::Error::source(&self.0)
66 | }
67 | }
68 |
69 | // If [`RawOsError`](https://doc.rust-lang.org/std/io/type.RawOsError.html) is stablized, we can use it.
70 |
71 | #[cfg(not(target_os = "uefi"))]
72 | type RawOsError = i32;
73 |
74 | #[cfg(target_os = "uefi")]
75 | type RawOsError = usize;
76 |
77 | impl OsError {
78 | /// Extract the raw OS error code (if this error came from the OS)
79 | ///
80 | /// This method is identical to [`std::io::Error::raw_os_error()`][1], except
81 | /// that it works in `no_std` contexts. If this method returns `None`, the
82 | /// error value can still be formatted via the `Display` implementation.
83 | ///
84 | /// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
85 | #[inline]
86 | pub fn raw_os_error(self) -> Option {
87 | self.0.raw_os_error()
88 | }
89 | }
90 |
91 | impl TryRngCore for OsRng {
92 | type Error = OsError;
93 |
94 | #[inline]
95 | fn try_next_u32(&mut self) -> Result {
96 | getrandom::u32().map_err(OsError)
97 | }
98 |
99 | #[inline]
100 | fn try_next_u64(&mut self) -> Result {
101 | getrandom::u64().map_err(OsError)
102 | }
103 |
104 | #[inline]
105 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
106 | getrandom::fill(dest).map_err(OsError)
107 | }
108 | }
109 |
110 | impl TryCryptoRng for OsRng {}
111 |
112 | #[test]
113 | fn test_os_rng() {
114 | let x = OsRng.try_next_u64().unwrap();
115 | let y = OsRng.try_next_u64().unwrap();
116 | assert!(x != 0);
117 | assert!(x != y);
118 | }
119 |
120 | #[test]
121 | fn test_construction() {
122 | assert!(OsRng.try_next_u64().unwrap() != 0);
123 | }
124 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Disclaimer
4 |
5 | Rand is a community project and cannot provide legally-binding guarantees of
6 | security.
7 |
8 | ## Security premises
9 |
10 | ### Marker traits
11 |
12 | Rand provides the marker traits `CryptoRng`, `TryCryptoRng` and
13 | `CryptoBlockRng`. Generators (RNGs) implementing one of these traits which are
14 | used according to these additional constraints:
15 |
16 | - The generator may be constructed using `std::default::Default` where the
17 | generator supports this trait. Note that generators should *only* support
18 | `Default` where the `default()` instance is appropriately seeded: for
19 | example `OsRng` has no state and thus has a trivial `default()` instance
20 | while `ThreadRng::default()` returns a handle to a thread-local instance
21 | seeded using `OsRng`.
22 | - The generator may be constructed using `rand_core::SeedableRng` in any of
23 | the following ways where the generator supports this trait:
24 |
25 | - Via `SeedableRng::from_seed` using a cryptographically secure seed value
26 | - Via `SeedableRng::from_rng` or `try_from_rng` using a cryptographically
27 | secure source `rng` such as `OsRng` or `ThreadRng`.
28 | - The state (memory) of the generator and its seed value (or source `rng`) are
29 | not exposed
30 |
31 | are expected to provide the following:
32 |
33 | - An attacker cannot predict the output with more accuracy than what would be
34 | expected through pure chance since each possible output value of any method
35 | under the above traits which generates output bytes (including
36 | `RngCore::next_u32`, `RngCore::next_u64`, `RngCore::fill_bytes`,
37 | `TryRngCore::try_next_u32`, `TryRngCore::try_next_u64`,
38 | `TryRngCore::try_fill_bytes` and `BlockRngCore::generate`) should be equally
39 | likely
40 | - Knowledge of prior outputs from the generator does not aid an attacker in
41 | predicting future outputs
42 |
43 | ### Specific generators
44 |
45 | `OsRng` is a stateless "generator" implemented via [getrandom]. As such, it has
46 | no possible state to leak and cannot be improperly seeded.
47 |
48 | `StdRng` is a `CryptoRng` and `SeedableRng` using a pseudo-random algorithm
49 | selected for good security and performance qualities. Since it does not offer
50 | reproducibility of output, its algorithm may be changed in any release version.
51 |
52 | `ChaCha12Rng` and `ChaCha20Rng` are selected pseudo-random generators
53 | distributed by the `rand` project which meet the requirements of the `CryptoRng`
54 | trait and implement `SeedableRng` with a commitment to reproducibility of
55 | results.
56 |
57 | `ThreadRng` is a conveniently-packaged generator over `StdRng` offering
58 | automatic seeding from `OsRng`, periodic reseeding and thread locality.
59 | This random source is intended to offer a good compromise between cryptographic
60 | security, fast generation with reasonably low memory and initialization cost
61 | overheads, and robustness against misuse.
62 |
63 | [getrandom]: https://crates.io/crates/getrandom
64 |
65 | ### Distributions
66 |
67 | Methods of the `Rng` trait, functionality of the `rand::seq` module and
68 | implementators of the `Distribution` trait are expected, while using a
69 | cryptographically secure `CryptoRng` instance meeting the above constraints,
70 | to not introduce significant bias to their operation beyond what would be
71 | expected of the operation. Note that the usage of 'significant' here permits
72 | some bias, as noted for example in the documentation of the `Uniform`
73 | distribution.
74 |
75 | ## Supported Versions
76 |
77 | We aim to provide security fixes in the form of a new patch version for the
78 | latest release version of `rand` and its dependencies `rand_core` and
79 | `rand_chacha`, as well as for prior major and minor releases which were, at some
80 | time during the previous 12 months, the latest release version.
81 |
82 | ## Reporting a Vulnerability
83 |
84 | If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released.
85 |
86 | Please disclose it at [security advisory](https://github.com/rust-random/rand/security/advisories/new).
87 |
88 | This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure.
89 |
--------------------------------------------------------------------------------
/examples/monty-hall.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | // Copyright 2013-2018 The Rust Project Developers.
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | //! ## Monty Hall Problem
11 | //!
12 | //! This is a simulation of the [Monty Hall Problem][]:
13 | //!
14 | //! > Suppose you're on a game show, and you're given the choice of three doors:
15 | //! > Behind one door is a car; behind the others, goats. You pick a door, say
16 | //! > No. 1, and the host, who knows what's behind the doors, opens another
17 | //! > door, say No. 3, which has a goat. He then says to you, "Do you want to
18 | //! > pick door No. 2?" Is it to your advantage to switch your choice?
19 | //!
20 | //! The rather unintuitive answer is that you will have a 2/3 chance of winning
21 | //! if you switch and a 1/3 chance of winning if you don't, so it's better to
22 | //! switch.
23 | //!
24 | //! This program will simulate the game show and with large enough simulation
25 | //! steps it will indeed confirm that it is better to switch.
26 | //!
27 | //! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem
28 |
29 | use rand::Rng;
30 | use rand::distr::{Distribution, Uniform};
31 |
32 | struct SimulationResult {
33 | win: bool,
34 | switch: bool,
35 | }
36 |
37 | // Run a single simulation of the Monty Hall problem.
38 | fn simulate(random_door: &Uniform, rng: &mut R) -> SimulationResult {
39 | let car = random_door.sample(rng);
40 |
41 | // This is our initial choice
42 | let mut choice = random_door.sample(rng);
43 |
44 | // The game host opens a door
45 | let open = game_host_open(car, choice, rng);
46 |
47 | // Shall we switch?
48 | let switch = rng.random();
49 | if switch {
50 | choice = switch_door(choice, open);
51 | }
52 |
53 | SimulationResult {
54 | win: choice == car,
55 | switch,
56 | }
57 | }
58 |
59 | // Returns the door the game host opens given our choice and knowledge of
60 | // where the car is. The game host will never open the door with the car.
61 | fn game_host_open(car: u32, choice: u32, rng: &mut R) -> u32 {
62 | use rand::seq::IndexedRandom;
63 | *free_doors(&[car, choice]).choose(rng).unwrap()
64 | }
65 |
66 | // Returns the door we switch to, given our current choice and
67 | // the open door. There will only be one valid door.
68 | fn switch_door(choice: u32, open: u32) -> u32 {
69 | free_doors(&[choice, open])[0]
70 | }
71 |
72 | fn free_doors(blocked: &[u32]) -> Vec {
73 | (0..3).filter(|x| !blocked.contains(x)).collect()
74 | }
75 |
76 | fn main() {
77 | // The estimation will be more accurate with more simulations
78 | let num_simulations = 10000;
79 |
80 | let mut rng = rand::rng();
81 | let random_door = Uniform::new(0u32, 3).unwrap();
82 |
83 | let (mut switch_wins, mut switch_losses) = (0, 0);
84 | let (mut keep_wins, mut keep_losses) = (0, 0);
85 |
86 | println!("Running {} simulations...", num_simulations);
87 | for _ in 0..num_simulations {
88 | let result = simulate(&random_door, &mut rng);
89 |
90 | match (result.win, result.switch) {
91 | (true, true) => switch_wins += 1,
92 | (true, false) => keep_wins += 1,
93 | (false, true) => switch_losses += 1,
94 | (false, false) => keep_losses += 1,
95 | }
96 | }
97 |
98 | let total_switches = switch_wins + switch_losses;
99 | let total_keeps = keep_wins + keep_losses;
100 |
101 | println!(
102 | "Switched door {} times with {} wins and {} losses",
103 | total_switches, switch_wins, switch_losses
104 | );
105 |
106 | println!(
107 | "Kept our choice {} times with {} wins and {} losses",
108 | total_keeps, keep_wins, keep_losses
109 | );
110 |
111 | // With a large number of simulations, the values should converge to
112 | // 0.667 and 0.333 respectively.
113 | println!(
114 | "Estimated chance to win if we switch: {}",
115 | switch_wins as f32 / total_switches as f32
116 | );
117 | println!(
118 | "Estimated chance to win if we don't: {}",
119 | keep_wins as f32 / total_keeps as f32
120 | );
121 | }
122 |
--------------------------------------------------------------------------------
/rand_chacha/src/lib.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! The ChaCha random number generators.
10 | //!
11 | //! These are native Rust implementations of RNGs derived from the
12 | //! [ChaCha stream ciphers] by D J Bernstein.
13 | //!
14 | //! ## Generators
15 | //!
16 | //! This crate provides 8-, 12- and 20-round variants of generators via a "core"
17 | //! implementation (of [`BlockRngCore`]), each with an associated "RNG" type
18 | //! (implementing [`RngCore`]).
19 | //!
20 | //! These generators are all deterministic and portable (see [Reproducibility]
21 | //! in the book), with testing against reference vectors.
22 | //!
23 | //! ## Cryptographic (secure) usage
24 | //!
25 | //! Where secure unpredictable generators are required, it is suggested to use
26 | //! [`ChaCha12Rng`] or [`ChaCha20Rng`] and to seed via
27 | //! [`OsRng`].
28 | //!
29 | //! See also the [Security] chapter in the rand book. The crate is provided
30 | //! "as is", without any form of guarantee, and without a security audit.
31 | //!
32 | //! ## Seeding (construction)
33 | //!
34 | //! Generators implement the [`SeedableRng`] trait. Any method may be used,
35 | //! but note that `seed_from_u64` is not suitable for usage where security is
36 | //! important. Some suggestions:
37 | //!
38 | //! 1. With a fresh seed, **direct from the OS** (implies a syscall):
39 | //! ```
40 | //! # use {rand_core::SeedableRng, rand_chacha::ChaCha12Rng, rand::rngs::OsRng};
41 | //! let rng = ChaCha12Rng::try_from_rng(&mut OsRng).unwrap();
42 | //! # let _: ChaCha12Rng = rng;
43 | //! ```
44 | //! 2. **From a master generator.** This could be [`rand::rng`]
45 | //! (effectively a fresh seed without the need for a syscall on each usage)
46 | //! or a deterministic generator such as [`ChaCha20Rng`].
47 | //! Beware that should a weak master generator be used, correlations may be
48 | //! detectable between the outputs of its child generators.
49 | //! ```ignore
50 | //! let rng = ChaCha12Rng::from_rng(&mut rand::rng());
51 | //! ```
52 | //!
53 | //! See also [Seeding RNGs] in the book.
54 | //!
55 | //! ## Generation
56 | //!
57 | //! Generators implement [`RngCore`], whose methods may be used directly to
58 | //! generate unbounded integer or byte values.
59 | //! ```
60 | //! use rand_core::{SeedableRng, RngCore};
61 | //! use rand_chacha::ChaCha12Rng;
62 | //!
63 | //! let mut rng = ChaCha12Rng::from_seed(Default::default());
64 | //! let x = rng.next_u64();
65 | //! assert_eq!(x, 0x53f955076a9af49b);
66 | //! ```
67 | //!
68 | //! It is often more convenient to use the [`rand::Rng`] trait, which provides
69 | //! further functionality. See also the [Random Values] chapter in the book.
70 | //!
71 | //! [ChaCha stream ciphers]: https://cr.yp.to/chacha.html
72 | //! [Reproducibility]: https://rust-random.github.io/book/crate-reprod.html
73 | //! [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html
74 | //! [Security]: https://rust-random.github.io/book/guide-rngs.html#security
75 | //! [Random Values]: https://rust-random.github.io/book/guide-values.html
76 | //! [`BlockRngCore`]: rand_core::block::BlockRngCore
77 | //! [`RngCore`]: rand_core::RngCore
78 | //! [`SeedableRng`]: rand_core::SeedableRng
79 | //! [`OsRng`]: https://docs.rs/rand/latest/rand/rngs/struct.OsRng.html
80 | //! [`rand::rng`]: https://docs.rs/rand/latest/rand/fn.rng.html
81 | //! [`rand::Rng`]: https://docs.rs/rand/latest/rand/trait.Rng.html
82 |
83 | #![doc(
84 | html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
85 | html_favicon_url = "https://www.rust-lang.org/favicon.ico"
86 | )]
87 | #![forbid(unsafe_code)]
88 | #![deny(missing_docs)]
89 | #![deny(missing_debug_implementations)]
90 | #![doc(test(attr(allow(unused_variables), deny(warnings))))]
91 | #![cfg_attr(not(feature = "std"), no_std)]
92 |
93 | pub use rand_core;
94 |
95 | mod chacha;
96 | mod guts;
97 |
98 | pub use crate::chacha::{
99 | ChaCha8Core, ChaCha8Rng, ChaCha12Core, ChaCha12Rng, ChaCha20Core, ChaCha20Rng,
100 | };
101 |
102 | /// ChaCha with 20 rounds
103 | pub type ChaChaRng = ChaCha20Rng;
104 | /// ChaCha with 20 rounds, low-level interface
105 | pub type ChaChaCore = ChaCha20Core;
106 |
--------------------------------------------------------------------------------
/benches/benches/uniform.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Implement benchmarks for uniform distributions over integer types
10 |
11 | #![cfg_attr(feature = "simd_support", feature(portable_simd))]
12 |
13 | use core::time::Duration;
14 | use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
15 | use rand::distr::uniform::{SampleRange, Uniform};
16 | use rand::prelude::*;
17 | use rand_chacha::ChaCha8Rng;
18 | use rand_pcg::{Pcg32, Pcg64};
19 | #[cfg(feature = "simd_support")]
20 | use std::simd::{Simd, num::SimdUint};
21 |
22 | const WARM_UP_TIME: Duration = Duration::from_millis(1000);
23 | const MEASUREMENT_TIME: Duration = Duration::from_secs(3);
24 | const SAMPLE_SIZE: usize = 100_000;
25 | const N_RESAMPLES: usize = 10_000;
26 |
27 | macro_rules! sample {
28 | (@range $T:ty, $U:ty, 1, $rng:ident) => {{
29 | assert_eq!(<$T>::BITS, <$U>::BITS);
30 | let bits = (<$T>::BITS / 2);
31 | let mask = (1 as $U).wrapping_neg() >> bits;
32 | let x = $rng.random::<$U>();
33 | ((x >> bits) * (x & mask)) as $T
34 | }};
35 |
36 | (@range $T:ty, $U:ty, $len:tt, $rng:ident) => {{
37 | let bits = (<$T>::BITS / 2);
38 | let mask = Simd::splat((1 as $U).wrapping_neg() >> bits);
39 | let bits = Simd::splat(bits as $U);
40 | let x = $rng.random::>();
41 | ((x >> bits) * (x & mask)).cast()
42 | }};
43 |
44 | (@MIN $T:ty, 1) => {
45 | <$T>::MIN
46 | };
47 |
48 | (@MIN $T:ty, $len:tt) => {
49 | Simd::<$T, $len>::splat(<$T>::MIN)
50 | };
51 |
52 | (@wrapping_add $lhs:expr, $rhs:expr, 1) => {
53 | $lhs.wrapping_add($rhs)
54 | };
55 |
56 | (@wrapping_add $lhs:expr, $rhs:expr, $len:tt) => {
57 | ($lhs + $rhs)
58 | };
59 |
60 | ($R:ty, $T:ty, $U:ty, $len:tt, $g:expr) => {
61 | $g.bench_function(BenchmarkId::new(stringify!($R), "single"), |b| {
62 | let mut rng = <$R>::from_rng(&mut rand::rng());
63 | let range = sample!(@range $T, $U, $len, rng);
64 | let low = sample!(@MIN $T, $len);
65 | let high = sample!(@wrapping_add low, range, $len);
66 |
67 | b.iter(|| (low..=high).sample_single(&mut rng));
68 | });
69 |
70 | $g.bench_function(BenchmarkId::new(stringify!($R), "distr"), |b| {
71 | let mut rng = <$R>::from_rng(&mut rand::rng());
72 | let range = sample!(@range $T, $U, $len, rng);
73 | let low = sample!(@MIN $T, $len);
74 | let high = sample!(@wrapping_add low, range, $len);
75 | let dist = Uniform::new_inclusive(low, high).unwrap();
76 |
77 | b.iter(|| dist.sample(&mut rng));
78 | });
79 | };
80 |
81 | // Entrypoint:
82 | // $T is the output type (integer)
83 | // $U is the unsigned version of the output type
84 | // $len is the width for SIMD or 1 for non-SIMD
85 | ($c:expr, $T:ty, $U:ty, $len:tt) => {{
86 | let mut g = $c.benchmark_group(concat!("sample_", stringify!($T), "x", stringify!($len)));
87 | g.sample_size(SAMPLE_SIZE);
88 | g.warm_up_time(WARM_UP_TIME);
89 | g.measurement_time(MEASUREMENT_TIME);
90 | g.nresamples(N_RESAMPLES);
91 | sample!(SmallRng, $T, $U, $len, g);
92 | sample!(ChaCha8Rng, $T, $U, $len, g);
93 | sample!(Pcg32, $T, $U, $len, g);
94 | sample!(Pcg64, $T, $U, $len, g);
95 | g.finish();
96 | }};
97 | }
98 |
99 | fn sample(c: &mut Criterion) {
100 | sample!(c, i8, u8, 1);
101 | sample!(c, i16, u16, 1);
102 | sample!(c, i32, u32, 1);
103 | sample!(c, i64, u64, 1);
104 | sample!(c, i128, u128, 1);
105 | #[cfg(feature = "simd_support")]
106 | sample!(c, u8, u8, 8);
107 | #[cfg(feature = "simd_support")]
108 | sample!(c, u8, u8, 16);
109 | #[cfg(feature = "simd_support")]
110 | sample!(c, u8, u8, 32);
111 | #[cfg(feature = "simd_support")]
112 | sample!(c, u8, u8, 64);
113 | #[cfg(feature = "simd_support")]
114 | sample!(c, i16, u16, 8);
115 | #[cfg(feature = "simd_support")]
116 | sample!(c, i16, u16, 16);
117 | #[cfg(feature = "simd_support")]
118 | sample!(c, i16, u16, 32);
119 | }
120 |
121 | criterion_group! {
122 | name = benches;
123 | config = Criterion::default();
124 | targets = sample
125 | }
126 | criterion_main!(benches);
127 |
--------------------------------------------------------------------------------
/src/rngs/small.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! A small fast RNG
10 |
11 | use rand_core::{RngCore, SeedableRng};
12 |
13 | #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))]
14 | type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus;
15 | #[cfg(target_pointer_width = "64")]
16 | type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus;
17 |
18 | /// A small-state, fast, non-crypto, non-portable PRNG
19 | ///
20 | /// This is the "standard small" RNG, a generator with the following properties:
21 | ///
22 | /// - Non-[portable]: any future library version may replace the algorithm
23 | /// and results may be platform-dependent.
24 | /// (For a small portable generator, use the [rand_pcg] or [rand_xoshiro] crate.)
25 | /// - Non-cryptographic: output is easy to predict (insecure)
26 | /// - [Quality]: statistically good quality
27 | /// - Fast: the RNG is fast for both bulk generation and single values, with
28 | /// consistent cost of method calls
29 | /// - Fast initialization
30 | /// - Small state: little memory usage (current state size is 16-32 bytes
31 | /// depending on platform)
32 | ///
33 | /// The current algorithm is
34 | /// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit
35 | /// platforms. Both are also implemented by the [rand_xoshiro] crate.
36 | ///
37 | /// ## Seeding (construction)
38 | ///
39 | /// This generator implements the [`SeedableRng`] trait. All methods are
40 | /// suitable for seeding, but note that, even with a fixed seed, output is not
41 | /// [portable]. Some suggestions:
42 | ///
43 | /// 1. To automatically seed with a unique seed, use [`SeedableRng::from_rng`]:
44 | /// ```
45 | /// use rand::SeedableRng;
46 | /// use rand::rngs::SmallRng;
47 | /// let rng = SmallRng::from_rng(&mut rand::rng());
48 | /// # let _: SmallRng = rng;
49 | /// ```
50 | /// 2. To use a deterministic integral seed, use `seed_from_u64`. This uses a
51 | /// hash function internally to yield a (typically) good seed from any
52 | /// input.
53 | /// ```
54 | /// # use rand::{SeedableRng, rngs::SmallRng};
55 | /// let rng = SmallRng::seed_from_u64(1);
56 | /// # let _: SmallRng = rng;
57 | /// ```
58 | /// 3. To seed deterministically from text or other input, use [`rand_seeder`].
59 | ///
60 | /// See also [Seeding RNGs] in the book.
61 | ///
62 | /// ## Generation
63 | ///
64 | /// The generators implements [`RngCore`] and thus also [`Rng`][crate::Rng].
65 | /// See also the [Random Values] chapter in the book.
66 | ///
67 | /// [portable]: https://rust-random.github.io/book/crate-reprod.html
68 | /// [Seeding RNGs]: https://rust-random.github.io/book/guide-seeding.html
69 | /// [Random Values]: https://rust-random.github.io/book/guide-values.html
70 | /// [Quality]: https://rust-random.github.io/book/guide-rngs.html#quality
71 | /// [`StdRng`]: crate::rngs::StdRng
72 | /// [rand_pcg]: https://crates.io/crates/rand_pcg
73 | /// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro
74 | /// [`rand_chacha::ChaCha8Rng`]: https://docs.rs/rand_chacha/latest/rand_chacha/struct.ChaCha8Rng.html
75 | /// [`rand_seeder`]: https://docs.rs/rand_seeder/latest/rand_seeder/
76 | #[derive(Clone, Debug, PartialEq, Eq)]
77 | pub struct SmallRng(Rng);
78 |
79 | impl SeedableRng for SmallRng {
80 | // Fix to 256 bits. Changing this is a breaking change!
81 | type Seed = [u8; 32];
82 |
83 | #[inline(always)]
84 | fn from_seed(seed: Self::Seed) -> Self {
85 | // This is for compatibility with 32-bit platforms where Rng::Seed has a different seed size
86 | // With MSRV >= 1.77: let seed = *seed.first_chunk().unwrap()
87 | const LEN: usize = core::mem::size_of::<::Seed>();
88 | let seed = (&seed[..LEN]).try_into().unwrap();
89 | SmallRng(Rng::from_seed(seed))
90 | }
91 |
92 | #[inline(always)]
93 | fn seed_from_u64(state: u64) -> Self {
94 | SmallRng(Rng::seed_from_u64(state))
95 | }
96 | }
97 |
98 | impl RngCore for SmallRng {
99 | #[inline(always)]
100 | fn next_u32(&mut self) -> u32 {
101 | self.0.next_u32()
102 | }
103 |
104 | #[inline(always)]
105 | fn next_u64(&mut self) -> u64 {
106 | self.0.next_u64()
107 | }
108 |
109 | #[inline(always)]
110 | fn fill_bytes(&mut self, dest: &mut [u8]) {
111 | self.0.fill_bytes(dest)
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/rngs/xoshiro128plusplus.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use rand_core::{RngCore, SeedableRng, le};
10 | #[cfg(feature = "serde")]
11 | use serde::{Deserialize, Serialize};
12 |
13 | /// A xoshiro128++ random number generator.
14 | ///
15 | /// The xoshiro128++ algorithm is not suitable for cryptographic purposes, but
16 | /// is very fast and has excellent statistical properties.
17 | ///
18 | /// The algorithm used here is translated from [the `xoshiro128plusplus.c`
19 | /// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.c) by
20 | /// David Blackman and Sebastiano Vigna.
21 | #[derive(Debug, Clone, PartialEq, Eq)]
22 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23 | pub struct Xoshiro128PlusPlus {
24 | s: [u32; 4],
25 | }
26 |
27 | impl SeedableRng for Xoshiro128PlusPlus {
28 | type Seed = [u8; 16];
29 |
30 | /// Create a new `Xoshiro128PlusPlus`. If `seed` is entirely 0, it will be
31 | /// mapped to a different seed.
32 | #[inline]
33 | fn from_seed(seed: [u8; 16]) -> Xoshiro128PlusPlus {
34 | let mut state = [0; 4];
35 | le::read_u32_into(&seed, &mut state);
36 | // Check for zero on aligned integers for better code generation.
37 | // Furtermore, seed_from_u64(0) will expand to a constant when optimized.
38 | if state.iter().all(|&x| x == 0) {
39 | return Self::seed_from_u64(0);
40 | }
41 | Xoshiro128PlusPlus { s: state }
42 | }
43 |
44 | /// Create a new `Xoshiro128PlusPlus` from a `u64` seed.
45 | ///
46 | /// This uses the SplitMix64 generator internally.
47 | #[inline]
48 | fn seed_from_u64(mut state: u64) -> Self {
49 | const PHI: u64 = 0x9e3779b97f4a7c15;
50 | let mut s = [0; 4];
51 | for i in s.chunks_exact_mut(2) {
52 | state = state.wrapping_add(PHI);
53 | let mut z = state;
54 | z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
55 | z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
56 | z = z ^ (z >> 31);
57 | i[0] = z as u32;
58 | i[1] = (z >> 32) as u32;
59 | }
60 | // By using a non-zero PHI we are guaranteed to generate a non-zero state
61 | // Thus preventing a recursion between from_seed and seed_from_u64.
62 | debug_assert_ne!(s, [0; 4]);
63 | Xoshiro128PlusPlus { s }
64 | }
65 | }
66 |
67 | impl RngCore for Xoshiro128PlusPlus {
68 | #[inline]
69 | fn next_u32(&mut self) -> u32 {
70 | let res = self.s[0]
71 | .wrapping_add(self.s[3])
72 | .rotate_left(7)
73 | .wrapping_add(self.s[0]);
74 |
75 | let t = self.s[1] << 9;
76 |
77 | self.s[2] ^= self.s[0];
78 | self.s[3] ^= self.s[1];
79 | self.s[1] ^= self.s[2];
80 | self.s[0] ^= self.s[3];
81 |
82 | self.s[2] ^= t;
83 |
84 | self.s[3] = self.s[3].rotate_left(11);
85 |
86 | res
87 | }
88 |
89 | #[inline]
90 | fn next_u64(&mut self) -> u64 {
91 | le::next_u64_via_u32(self)
92 | }
93 |
94 | #[inline]
95 | fn fill_bytes(&mut self, dst: &mut [u8]) {
96 | le::fill_bytes_via_next(self, dst)
97 | }
98 | }
99 |
100 | #[cfg(test)]
101 | mod tests {
102 | use super::Xoshiro128PlusPlus;
103 | use rand_core::{RngCore, SeedableRng};
104 |
105 | #[test]
106 | fn reference() {
107 | let mut rng =
108 | Xoshiro128PlusPlus::from_seed([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
109 | // These values were produced with the reference implementation:
110 | // http://xoshiro.di.unimi.it/xoshiro128plusplus.c
111 | let expected = [
112 | 641, 1573767, 3222811527, 3517856514, 836907274, 4247214768, 3867114732, 1355841295,
113 | 495546011, 621204420,
114 | ];
115 | for &e in &expected {
116 | assert_eq!(rng.next_u32(), e);
117 | }
118 | }
119 |
120 | #[test]
121 | fn stable_seed_from_u64_and_from_seed() {
122 | // We don't guarantee value-stability for SmallRng but this
123 | // could influence keeping stability whenever possible (e.g. after optimizations).
124 | let mut rng = Xoshiro128PlusPlus::seed_from_u64(0);
125 | // from_seed([0; 16]) should produce the same state as seed_from_u64(0).
126 | let mut rng_from_seed_0 = Xoshiro128PlusPlus::from_seed([0; 16]);
127 | let expected = [
128 | 1179900579, 1938959192, 3089844957, 3657088315, 1015453891, 479942911, 3433842246,
129 | 669252886, 3985671746, 2737205563,
130 | ];
131 | for &e in &expected {
132 | assert_eq!(rng.next_u32(), e);
133 | assert_eq!(rng_from_seed_0.next_u32(), e);
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/rngs/xoshiro256plusplus.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use rand_core::{RngCore, SeedableRng, le};
10 | #[cfg(feature = "serde")]
11 | use serde::{Deserialize, Serialize};
12 |
13 | /// A xoshiro256++ random number generator.
14 | ///
15 | /// The xoshiro256++ algorithm is not suitable for cryptographic purposes, but
16 | /// is very fast and has excellent statistical properties.
17 | ///
18 | /// The algorithm used here is translated from [the `xoshiro256plusplus.c`
19 | /// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by
20 | /// David Blackman and Sebastiano Vigna.
21 | #[derive(Debug, Clone, PartialEq, Eq)]
22 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23 | pub struct Xoshiro256PlusPlus {
24 | s: [u64; 4],
25 | }
26 |
27 | impl SeedableRng for Xoshiro256PlusPlus {
28 | type Seed = [u8; 32];
29 |
30 | /// Create a new `Xoshiro256PlusPlus`. If `seed` is entirely 0, it will be
31 | /// mapped to a different seed.
32 | #[inline]
33 | fn from_seed(seed: [u8; 32]) -> Xoshiro256PlusPlus {
34 | let mut state = [0; 4];
35 | le::read_u64_into(&seed, &mut state);
36 | // Check for zero on aligned integers for better code generation.
37 | // Furtermore, seed_from_u64(0) will expand to a constant when optimized.
38 | if state.iter().all(|&x| x == 0) {
39 | return Self::seed_from_u64(0);
40 | }
41 | Xoshiro256PlusPlus { s: state }
42 | }
43 |
44 | /// Create a new `Xoshiro256PlusPlus` from a `u64` seed.
45 | ///
46 | /// This uses the SplitMix64 generator internally.
47 | #[inline]
48 | fn seed_from_u64(mut state: u64) -> Self {
49 | const PHI: u64 = 0x9e3779b97f4a7c15;
50 | let mut s = [0; 4];
51 | for i in s.iter_mut() {
52 | state = state.wrapping_add(PHI);
53 | let mut z = state;
54 | z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
55 | z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
56 | z = z ^ (z >> 31);
57 | *i = z;
58 | }
59 | // By using a non-zero PHI we are guaranteed to generate a non-zero state
60 | // Thus preventing a recursion between from_seed and seed_from_u64.
61 | debug_assert_ne!(s, [0; 4]);
62 | Xoshiro256PlusPlus { s }
63 | }
64 | }
65 |
66 | impl RngCore for Xoshiro256PlusPlus {
67 | #[inline]
68 | fn next_u32(&mut self) -> u32 {
69 | // The lowest bits have some linear dependencies, so we use the
70 | // upper bits instead.
71 | let val = self.next_u64();
72 | (val >> 32) as u32
73 | }
74 |
75 | #[inline]
76 | fn next_u64(&mut self) -> u64 {
77 | let res = self.s[0]
78 | .wrapping_add(self.s[3])
79 | .rotate_left(23)
80 | .wrapping_add(self.s[0]);
81 |
82 | let t = self.s[1] << 17;
83 |
84 | self.s[2] ^= self.s[0];
85 | self.s[3] ^= self.s[1];
86 | self.s[1] ^= self.s[2];
87 | self.s[0] ^= self.s[3];
88 |
89 | self.s[2] ^= t;
90 |
91 | self.s[3] = self.s[3].rotate_left(45);
92 |
93 | res
94 | }
95 |
96 | #[inline]
97 | fn fill_bytes(&mut self, dst: &mut [u8]) {
98 | le::fill_bytes_via_next(self, dst)
99 | }
100 | }
101 |
102 | #[cfg(test)]
103 | mod tests {
104 | use super::Xoshiro256PlusPlus;
105 | use rand_core::{RngCore, SeedableRng};
106 |
107 | #[test]
108 | fn reference() {
109 | let mut rng = Xoshiro256PlusPlus::from_seed([
110 | 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
111 | 0, 0, 0,
112 | ]);
113 | // These values were produced with the reference implementation:
114 | // http://xoshiro.di.unimi.it/xoshiro256plusplus.c
115 | let expected = [
116 | 41943041,
117 | 58720359,
118 | 3588806011781223,
119 | 3591011842654386,
120 | 9228616714210784205,
121 | 9973669472204895162,
122 | 14011001112246962877,
123 | 12406186145184390807,
124 | 15849039046786891736,
125 | 10450023813501588000,
126 | ];
127 | for &e in &expected {
128 | assert_eq!(rng.next_u64(), e);
129 | }
130 | }
131 |
132 | #[test]
133 | fn stable_seed_from_u64_and_from_seed() {
134 | // We don't guarantee value-stability for SmallRng but this
135 | // could influence keeping stability whenever possible (e.g. after optimizations).
136 | let mut rng = Xoshiro256PlusPlus::seed_from_u64(0);
137 | // from_seed([0; 32]) should produce the same state as seed_from_u64(0).
138 | let mut rng_from_seed_0 = Xoshiro256PlusPlus::from_seed([0; 32]);
139 | let expected = [
140 | 5987356902031041503,
141 | 7051070477665621255,
142 | 6633766593972829180,
143 | 211316841551650330,
144 | 9136120204379184874,
145 | 379361710973160858,
146 | 15813423377499357806,
147 | 15596884590815070553,
148 | 5439680534584881407,
149 | 1369371744833522710,
150 | ];
151 | for &e in &expected {
152 | assert_eq!(rng.next_u64(), e);
153 | assert_eq!(rng_from_seed_0.next_u64(), e);
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/distr/slice.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Distributions over slices
10 |
11 | use core::num::NonZeroUsize;
12 |
13 | use crate::distr::Distribution;
14 | use crate::distr::uniform::{UniformSampler, UniformUsize};
15 | #[cfg(feature = "alloc")]
16 | use alloc::string::String;
17 |
18 | /// A distribution to uniformly sample elements of a slice
19 | ///
20 | /// Like [`IndexedRandom::choose`], this uniformly samples elements of a slice
21 | /// without modification of the slice (so called "sampling with replacement").
22 | /// This distribution object may be a little faster for repeated sampling (but
23 | /// slower for small numbers of samples).
24 | ///
25 | /// ## Examples
26 | ///
27 | /// Since this is a distribution, [`Rng::sample_iter`] and
28 | /// [`Distribution::sample_iter`] may be used, for example:
29 | /// ```
30 | /// use rand::distr::{Distribution, slice::Choose};
31 | ///
32 | /// let vowels = ['a', 'e', 'i', 'o', 'u'];
33 | /// let vowels_dist = Choose::new(&vowels).unwrap();
34 | ///
35 | /// // build a string of 10 vowels
36 | /// let vowel_string: String = vowels_dist
37 | /// .sample_iter(&mut rand::rng())
38 | /// .take(10)
39 | /// .collect();
40 | ///
41 | /// println!("{}", vowel_string);
42 | /// assert_eq!(vowel_string.len(), 10);
43 | /// assert!(vowel_string.chars().all(|c| vowels.contains(&c)));
44 | /// ```
45 | ///
46 | /// For a single sample, [`IndexedRandom::choose`] may be preferred:
47 | /// ```
48 | /// use rand::seq::IndexedRandom;
49 | ///
50 | /// let vowels = ['a', 'e', 'i', 'o', 'u'];
51 | /// let mut rng = rand::rng();
52 | ///
53 | /// println!("{}", vowels.choose(&mut rng).unwrap());
54 | /// ```
55 | ///
56 | /// [`IndexedRandom::choose`]: crate::seq::IndexedRandom::choose
57 | /// [`Rng::sample_iter`]: crate::Rng::sample_iter
58 | #[derive(Debug, Clone, Copy)]
59 | pub struct Choose<'a, T> {
60 | slice: &'a [T],
61 | range: UniformUsize,
62 | num_choices: NonZeroUsize,
63 | }
64 |
65 | impl<'a, T> Choose<'a, T> {
66 | /// Create a new `Choose` instance which samples uniformly from the slice.
67 | ///
68 | /// Returns error [`Empty`] if the slice is empty.
69 | pub fn new(slice: &'a [T]) -> Result {
70 | let num_choices = NonZeroUsize::new(slice.len()).ok_or(Empty)?;
71 |
72 | Ok(Self {
73 | slice,
74 | range: UniformUsize::new(0, num_choices.get()).unwrap(),
75 | num_choices,
76 | })
77 | }
78 |
79 | /// Returns the count of choices in this distribution
80 | pub fn num_choices(&self) -> NonZeroUsize {
81 | self.num_choices
82 | }
83 | }
84 |
85 | impl<'a, T> Distribution<&'a T> for Choose<'a, T> {
86 | fn sample(&self, rng: &mut R) -> &'a T {
87 | let idx = self.range.sample(rng);
88 |
89 | debug_assert!(
90 | idx < self.slice.len(),
91 | "Uniform::new(0, {}) somehow returned {}",
92 | self.slice.len(),
93 | idx
94 | );
95 |
96 | // Safety: at construction time, it was ensured that the slice was
97 | // non-empty, and that the `Uniform` range produces values in range
98 | // for the slice
99 | unsafe { self.slice.get_unchecked(idx) }
100 | }
101 | }
102 |
103 | /// Error: empty slice
104 | ///
105 | /// This error is returned when [`Choose::new`] is given an empty slice.
106 | #[derive(Debug, Clone, Copy)]
107 | pub struct Empty;
108 |
109 | impl core::fmt::Display for Empty {
110 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
111 | write!(
112 | f,
113 | "Tried to create a `rand::distr::slice::Choose` with an empty slice"
114 | )
115 | }
116 | }
117 |
118 | #[cfg(feature = "std")]
119 | impl std::error::Error for Empty {}
120 |
121 | #[cfg(feature = "alloc")]
122 | impl super::SampleString for Choose<'_, char> {
123 | fn append_string(&self, rng: &mut R, string: &mut String, len: usize) {
124 | // Get the max char length to minimize extra space.
125 | // Limit this check to avoid searching for long slice.
126 | let max_char_len = if self.slice.len() < 200 {
127 | self.slice
128 | .iter()
129 | .try_fold(1, |max_len, char| {
130 | // When the current max_len is 4, the result max_char_len will be 4.
131 | Some(max_len.max(char.len_utf8())).filter(|len| *len < 4)
132 | })
133 | .unwrap_or(4)
134 | } else {
135 | 4
136 | };
137 |
138 | // Split the extension of string to reuse the unused capacities.
139 | // Skip the split for small length or only ascii slice.
140 | let mut extend_len = if max_char_len == 1 || len < 100 {
141 | len
142 | } else {
143 | len / 4
144 | };
145 | let mut remain_len = len;
146 | while extend_len > 0 {
147 | string.reserve(max_char_len * extend_len);
148 | string.extend(self.sample_iter(&mut *rng).take(extend_len));
149 | remain_len -= extend_len;
150 | extend_len = extend_len.min(remain_len);
151 | }
152 | }
153 | }
154 |
155 | #[cfg(test)]
156 | mod test {
157 | use super::*;
158 | use core::iter;
159 |
160 | #[test]
161 | fn value_stability() {
162 | let rng = crate::test::rng(651);
163 | let slice = Choose::new(b"escaped emus explore extensively").unwrap();
164 | let expected = b"eaxee";
165 | assert!(iter::zip(slice.sample_iter(rng), expected).all(|(a, b)| a == b));
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/rngs/mod.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Random number generators and adapters
10 | //!
11 | //! ## Generators
12 | //!
13 | //! This crate provides a small selection of generators.
14 | //! See also [Types of generators] and [Our RNGs] in the book.
15 | //!
16 | //! ##### Non-deterministic generators
17 | //!
18 | //! - [`OsRng`] is a stateless interface over the operating system's random number
19 | //! source. This is typically secure with some form of periodic re-seeding.
20 | //! - [`ThreadRng`], provided by [`crate::rng()`], is a handle to a
21 | //! thread-local generator with periodic seeding from [`OsRng`]. Because this
22 | //! is local, it is typically much faster than [`OsRng`]. It should be
23 | //! secure, but see documentation on [`ThreadRng`].
24 | //!
25 | //! ##### Standard generators
26 | //!
27 | //! These use selected best-in-class algorithms. They are deterministic but not
28 | //! portable: the algorithms may be changed in any release and may be
29 | //! platform-dependent.
30 | //!
31 | //! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security
32 | //! (based on reviews, maturity and usage). The current algorithm is
33 | //! [`ChaCha12Rng`], which is well established and rigorously analysed.
34 | //! [`StdRng`] is the deterministic generator used by [`ThreadRng`] but
35 | //! without the periodic reseeding or thread-local management.
36 | //! - [`SmallRng`] is a relatively simple, insecure generator designed to be
37 | //! fast, use little memory, and pass various statistical tests of
38 | //! randomness quality. The current algorithm is one of the Xoshiro
39 | //! generators below, depending on the target's pointer size.
40 | //!
41 | //! ##### Named portable generators
42 | //!
43 | //! These are similar to the [standard generators](#standard-generators), but
44 | //! with the additional [guarantees of reproducibility]:
45 | //!
46 | //! - [`Xoshiro256PlusPlus`] is a very fast 64-bit insecure generator using
47 | //! 256 bits of state with good performance in statistical tests of quality
48 | //! - [`Xoshiro128PlusPlus`] is a very fast 32-bit insecure generator using
49 | //! 128 bits of state with good performance in statistical tests of quality
50 | //! - [`ChaCha8Rng`], [`ChaCha12Rng`] and [`ChaCha20Rng`] are generators over
51 | //! the ChaCha stream cipher designed by Daniel J. Bernstein[^1].
52 | //!
53 | //! ### Additional generators
54 | //!
55 | //! - The [`rdrand`] crate provides an interface to the RDRAND and RDSEED
56 | //! instructions available in modern Intel and AMD CPUs.
57 | //! - The [`rand_jitter`] crate provides a user-space implementation of
58 | //! entropy harvesting from CPU timer jitter, but is very slow and has
59 | //! [security issues](https://github.com/rust-random/rand/issues/699).
60 | //! - The [`rand_chacha`] crate provides portable implementations of
61 | //! generators derived from the [ChaCha] family of stream ciphers
62 | //! - The [`rand_pcg`] crate provides portable implementations of a subset
63 | //! of the [PCG] family of small, insecure generators
64 | //! - The [`rand_xoshiro`] crate provides portable implementations of the
65 | //! [xoshiro] family of small, insecure generators
66 | //!
67 | //! For more, search [crates with the `rng` tag].
68 | //!
69 | //! ## Traits and functionality
70 | //!
71 | //! All generators implement [`RngCore`] and thus also [`Rng`][crate::Rng].
72 | //! See also the [Random Values] chapter in the book.
73 | //!
74 | //! Secure RNGs may additionally implement the [`CryptoRng`] trait.
75 | //!
76 | //! Use the [`rand_core`] crate when implementing your own RNGs.
77 | //!
78 | //! [^1]: D. J. Bernstein, [*ChaCha, a variant of Salsa20*](https://cr.yp.to/chacha.html)
79 | //!
80 | //! [guarantees of reproducibility]: https://rust-random.github.io/book/crate-reprod.html
81 | //! [Types of generators]: https://rust-random.github.io/book/guide-gen.html
82 | //! [Our RNGs]: https://rust-random.github.io/book/guide-rngs.html
83 | //! [Random Values]: https://rust-random.github.io/book/guide-values.html
84 | //! [`Rng`]: crate::Rng
85 | //! [`RngCore`]: crate::RngCore
86 | //! [`CryptoRng`]: crate::CryptoRng
87 | //! [`SeedableRng`]: crate::SeedableRng
88 | //! [`rdrand`]: https://crates.io/crates/rdrand
89 | //! [`rand_jitter`]: https://crates.io/crates/rand_jitter
90 | //! [`rand_chacha`]: https://crates.io/crates/rand_chacha
91 | //! [`rand_pcg`]: https://crates.io/crates/rand_pcg
92 | //! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro
93 | //! [crates with the `rng` tag]: https://crates.io/keywords/rng
94 | //! [chacha]: https://cr.yp.to/chacha.html
95 | //! [PCG]: https://www.pcg-random.org/
96 | //! [xoshiro]: https://prng.di.unimi.it/
97 |
98 | mod reseeding;
99 | pub use reseeding::ReseedingRng;
100 |
101 | #[cfg(feature = "small_rng")]
102 | mod small;
103 | #[cfg(feature = "small_rng")]
104 | mod xoshiro128plusplus;
105 | #[cfg(feature = "small_rng")]
106 | mod xoshiro256plusplus;
107 |
108 | #[cfg(feature = "std_rng")]
109 | mod std;
110 | #[cfg(feature = "thread_rng")]
111 | pub(crate) mod thread;
112 |
113 | #[cfg(feature = "os_rng")]
114 | mod os;
115 |
116 | #[cfg(feature = "small_rng")]
117 | pub use self::small::SmallRng;
118 | #[cfg(feature = "small_rng")]
119 | pub use xoshiro128plusplus::Xoshiro128PlusPlus;
120 | #[cfg(feature = "small_rng")]
121 | pub use xoshiro256plusplus::Xoshiro256PlusPlus;
122 |
123 | #[cfg(feature = "std_rng")]
124 | pub use self::std::StdRng;
125 | #[cfg(feature = "thread_rng")]
126 | pub use self::thread::ThreadRng;
127 |
128 | #[cfg(feature = "chacha")]
129 | pub use chacha20::{ChaCha8Rng, ChaCha12Rng, ChaCha20Rng};
130 |
131 | #[cfg(feature = "os_rng")]
132 | pub use os::{OsError, OsRng};
133 |
--------------------------------------------------------------------------------
/rand_pcg/src/pcg64.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | // Copyright 2017 Paul Dicker.
3 | // Copyright 2014-2017 Melissa O'Neill and PCG Project contributors
4 | //
5 | // Licensed under the Apache License, Version 2.0 or the MIT license
7 | // , at your
8 | // option. This file may not be copied, modified, or distributed
9 | // except according to those terms.
10 |
11 | //! PCG random number generators
12 |
13 | use core::fmt;
14 | use rand_core::{RngCore, SeedableRng, le};
15 | #[cfg(feature = "serde")]
16 | use serde::{Deserialize, Serialize};
17 |
18 | // This is the default multiplier used by PCG for 64-bit state.
19 | const MULTIPLIER: u64 = 6364136223846793005;
20 |
21 | /// A PCG random number generator (XSH RR 64/32 (LCG) variant).
22 | ///
23 | /// Permuted Congruential Generator with 64-bit state, internal Linear
24 | /// Congruential Generator, and 32-bit output via "xorshift high (bits),
25 | /// random rotation" output function.
26 | ///
27 | /// This is a 64-bit LCG with explicitly chosen stream with the PCG-XSH-RR
28 | /// output function. This combination is the standard `pcg32`.
29 | ///
30 | /// Despite the name, this implementation uses 16 bytes (128 bit) space
31 | /// comprising 64 bits of state and 64 bits stream selector. These are both set
32 | /// by `SeedableRng`, using a 128-bit seed.
33 | ///
34 | /// Note that two generators with different stream parameter may be closely
35 | /// correlated.
36 | #[derive(Clone, PartialEq, Eq)]
37 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38 | pub struct Lcg64Xsh32 {
39 | state: u64,
40 | increment: u64,
41 | }
42 |
43 | /// [`Lcg64Xsh32`] is also officially known as `pcg32`.
44 | pub type Pcg32 = Lcg64Xsh32;
45 |
46 | impl Lcg64Xsh32 {
47 | /// Multi-step advance functions (jump-ahead, jump-back)
48 | ///
49 | /// The method used here is based on Brown, "Random Number Generation
50 | /// with Arbitrary Stride,", Transactions of the American Nuclear
51 | /// Society (Nov. 1994). The algorithm is very similar to fast
52 | /// exponentiation.
53 | ///
54 | /// Even though delta is an unsigned integer, we can pass a
55 | /// signed integer to go backwards, it just goes "the long way round".
56 | ///
57 | /// Using this function is equivalent to calling `next_32()` `delta`
58 | /// number of times.
59 | #[inline]
60 | pub fn advance(&mut self, delta: u64) {
61 | let mut acc_mult: u64 = 1;
62 | let mut acc_plus: u64 = 0;
63 | let mut cur_mult = MULTIPLIER;
64 | let mut cur_plus = self.increment;
65 | let mut mdelta = delta;
66 |
67 | while mdelta > 0 {
68 | if (mdelta & 1) != 0 {
69 | acc_mult = acc_mult.wrapping_mul(cur_mult);
70 | acc_plus = acc_plus.wrapping_mul(cur_mult).wrapping_add(cur_plus);
71 | }
72 | cur_plus = cur_mult.wrapping_add(1).wrapping_mul(cur_plus);
73 | cur_mult = cur_mult.wrapping_mul(cur_mult);
74 | mdelta /= 2;
75 | }
76 | self.state = acc_mult.wrapping_mul(self.state).wrapping_add(acc_plus);
77 | }
78 |
79 | /// Construct an instance compatible with PCG seed and stream.
80 | ///
81 | /// Note that the highest bit of the `stream` parameter is discarded
82 | /// to simplify upholding internal invariants.
83 | ///
84 | /// Note that two generators with different stream parameters may be closely
85 | /// correlated.
86 | ///
87 | /// PCG specifies the following default values for both parameters:
88 | ///
89 | /// - `state = 0xcafef00dd15ea5e5`
90 | /// - `stream = 0xa02bdbf7bb3c0a7`
91 | // Note: stream is 1442695040888963407u64 >> 1
92 | pub fn new(state: u64, stream: u64) -> Self {
93 | // The increment must be odd, hence we discard one bit:
94 | let increment = (stream << 1) | 1;
95 | Lcg64Xsh32::from_state_incr(state, increment)
96 | }
97 |
98 | #[inline]
99 | fn from_state_incr(state: u64, increment: u64) -> Self {
100 | let mut pcg = Lcg64Xsh32 { state, increment };
101 | // Move away from initial value:
102 | pcg.state = pcg.state.wrapping_add(pcg.increment);
103 | pcg.step();
104 | pcg
105 | }
106 |
107 | #[inline]
108 | fn step(&mut self) {
109 | // prepare the LCG for the next round
110 | self.state = self
111 | .state
112 | .wrapping_mul(MULTIPLIER)
113 | .wrapping_add(self.increment);
114 | }
115 | }
116 |
117 | // Custom Debug implementation that does not expose the internal state
118 | impl fmt::Debug for Lcg64Xsh32 {
119 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120 | write!(f, "Lcg64Xsh32 {{}}")
121 | }
122 | }
123 |
124 | impl SeedableRng for Lcg64Xsh32 {
125 | type Seed = [u8; 16];
126 |
127 | /// We use a single 127-bit seed to initialise the state and select a stream.
128 | /// One `seed` bit (lowest bit of `seed[8]`) is ignored.
129 | fn from_seed(seed: Self::Seed) -> Self {
130 | let mut seed_u64 = [0u64; 2];
131 | le::read_u64_into(&seed, &mut seed_u64);
132 |
133 | // The increment must be odd, hence we discard one bit:
134 | Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1)
135 | }
136 | }
137 |
138 | impl RngCore for Lcg64Xsh32 {
139 | #[inline]
140 | fn next_u32(&mut self) -> u32 {
141 | let state = self.state;
142 | self.step();
143 |
144 | // Output function XSH RR: xorshift high (bits), followed by a random rotate
145 | // Constants are for 64-bit state, 32-bit output
146 | const ROTATE: u32 = 59; // 64 - 5
147 | const XSHIFT: u32 = 18; // (5 + 32) / 2
148 | const SPARE: u32 = 27; // 64 - 32 - 5
149 |
150 | let rot = (state >> ROTATE) as u32;
151 | let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32;
152 | xsh.rotate_right(rot)
153 | }
154 |
155 | #[inline]
156 | fn next_u64(&mut self) -> u64 {
157 | le::next_u64_via_u32(self)
158 | }
159 |
160 | #[inline]
161 | fn fill_bytes(&mut self, dest: &mut [u8]) {
162 | le::fill_bytes_via_next(self, dest)
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rand
2 |
3 | [](https://github.com/rust-random/rand/actions)
4 | [](https://crates.io/crates/rand)
5 | [](https://rust-random.github.io/book/)
6 | [](https://docs.rs/rand)
7 |
8 | Rand is a set of crates supporting (pseudo-)random generators:
9 |
10 | - Built over a standard RNG trait: [`rand_core::RngCore`](https://docs.rs/rand_core/latest/rand_core/trait.RngCore.html)
11 | - With fast implementations of both [strong](https://rust-random.github.io/book/guide-rngs.html#cryptographically-secure-pseudo-random-number-generators-csprngs) and
12 | [small](https://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs) generators: [`rand::rngs`](https://docs.rs/rand/latest/rand/rngs/index.html), and more RNGs: [`rand_chacha`](https://docs.rs/rand_chacha), [`rand_xoshiro`](https://docs.rs/rand_xoshiro/), [`rand_pcg`](https://docs.rs/rand_pcg/), [rngs repo](https://github.com/rust-random/rngs/)
13 | - [`rand::rng`](https://docs.rs/rand/latest/rand/fn.rng.html) is an asymptotically-fast, automatically-seeded and reasonably strong generator available on all `std` targets
14 | - Direct support for seeding generators from the [getrandom] crate
15 |
16 | With broad support for random value generation and random processes:
17 |
18 | - [`StandardUniform`](https://docs.rs/rand/latest/rand/distr/struct.StandardUniform.html) random value sampling,
19 | [`Uniform`](https://docs.rs/rand/latest/rand/distr/struct.Uniform.html)-ranged value sampling
20 | and [more](https://docs.rs/rand/latest/rand/distr/index.html)
21 | - Samplers for a large number of non-uniform random number distributions via our own
22 | [`rand_distr`](https://docs.rs/rand_distr) and via
23 | the [`statrs`](https://docs.rs/statrs)
24 | - Random processes (mostly choose and shuffle) via [`rand::seq`](https://docs.rs/rand/latest/rand/seq/index.html) traits
25 |
26 | All with:
27 |
28 | - [Portably reproducible output](https://rust-random.github.io/book/portability.html)
29 | - `#[no_std]` compatibility (partial)
30 | - *Many* performance optimisations thanks to contributions from the wide
31 | user-base
32 |
33 | Rand **is not**:
34 |
35 | - Small (LoC). Most low-level crates are small, but the higher-level `rand`
36 | and `rand_distr` each contain a lot of functionality.
37 | - Simple (implementation). We have a strong focus on correctness, speed and flexibility, but
38 | not simplicity. If you prefer a small-and-simple library, there are
39 | alternatives including [fastrand](https://crates.io/crates/fastrand)
40 | and [oorandom](https://crates.io/crates/oorandom).
41 | - Primarily a cryptographic library. `rand` does provide some generators which
42 | aim to support unpredictable value generation under certain constraints;
43 | see [SECURITY.md](https://github.com/rust-random/rand/blob/master/SECURITY.md) for details.
44 | Users are expected to determine for themselves
45 | whether `rand`'s functionality meets their own security requirements.
46 |
47 | Documentation:
48 |
49 | - [The Rust Rand Book](https://rust-random.github.io/book)
50 | - [API reference (docs.rs)](https://docs.rs/rand)
51 |
52 |
53 | ## Versions
54 |
55 | Rand is *mature* (suitable for general usage, with infrequent breaking releases
56 | which minimise breakage) but not yet at 1.0. Current `MAJOR.MINOR` versions are:
57 |
58 | - Version 0.9 was released in January 2025.
59 |
60 | See the [CHANGELOG](https://github.com/rust-random/rand/blob/master/CHANGELOG.md) or [Upgrade Guide](https://rust-random.github.io/book/update.html) for more details.
61 |
62 | ## Crate Features
63 |
64 | Rand is built with these features enabled by default:
65 |
66 | - `std` enables functionality dependent on the `std` lib
67 | - `alloc` (implied by `std`) enables functionality requiring an allocator
68 | - `os_rng` (implied by `std`) enables `rngs::OsRng`, using the [getrandom] crate
69 | - `std_rng` enables inclusion of `StdRng`, `ThreadRng`
70 | - `small_rng` enables inclusion of the `SmallRng` PRNG
71 |
72 | Optionally, the following dependencies can be enabled:
73 |
74 | - `log` enables logging via [log](https://crates.io/crates/log)
75 |
76 | Additionally, these features configure Rand:
77 |
78 | - `nightly` includes some additions requiring nightly Rust
79 | - `simd_support` (experimental) enables sampling of SIMD values
80 | (uniformly random SIMD integers and floats), requiring nightly Rust
81 | - `unbiased` use unbiased sampling for algorithms supporting this option: Uniform distribution.
82 |
83 | (By default, bias affecting no more than one in 2^48 samples is accepted.)
84 |
85 | Note: enabling this option is expected to affect reproducibility of results.
86 |
87 | Note that nightly features are not stable and therefore not all library and
88 | compiler versions will be compatible. This is especially true of Rand's
89 | experimental `simd_support` feature.
90 |
91 | Rand supports limited functionality in `no_std` mode (enabled via
92 | `default-features = false`). In this case, `OsRng` is
93 | unavailable (unless `os_rng` is enabled), large parts of `seq` are
94 | unavailable (unless `alloc` is enabled), and `ThreadRng` is unavailable.
95 |
96 | ## Portability and platform support
97 |
98 | Many (but not all) algorithms are intended to have reproducible output. Read more in the book: [Portability](https://rust-random.github.io/book/portability.html).
99 |
100 | The Rand library supports a variety of CPU architectures. Platform integration is outsourced to [getrandom].
101 |
102 | ### WebAssembly support
103 |
104 | The [WASI](https://github.com/WebAssembly/WASI/tree/main) and Emscripten
105 | targets are directly supported. The `wasm32-unknown-unknown` target is not
106 | *automatically* supported. To enable support for this target, refer to the
107 | [`getrandom` documentation for WebAssembly](https://docs.rs/getrandom/latest/getrandom/#webassembly-support).
108 | Alternatively, the `os_rng` feature may be disabled.
109 |
110 | # License
111 |
112 | Rand is distributed under the terms of both the MIT license and the
113 | Apache License (Version 2.0).
114 |
115 | See [LICENSE-APACHE](https://github.com/rust-random/rand/blob/master/LICENSE-APACHE) and [LICENSE-MIT](https://github.com/rust-random/rand/blob/master/LICENSE-MIT), and
116 | [COPYRIGHT](https://github.com/rust-random/rand/blob/master/COPYRIGHT) for details.
117 |
118 | [getrandom]: https://crates.io/crates/getrandom
119 |
--------------------------------------------------------------------------------
/benches/benches/seq_choose.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use criterion::{Criterion, black_box, criterion_group, criterion_main};
10 | use rand::SeedableRng;
11 | use rand::prelude::*;
12 | use rand_pcg::Pcg32;
13 |
14 | criterion_group!(
15 | name = benches;
16 | config = Criterion::default();
17 | targets = bench
18 | );
19 | criterion_main!(benches);
20 |
21 | pub fn bench(c: &mut Criterion) {
22 | c.bench_function("seq_slice_choose_1_of_100", |b| {
23 | let mut rng = Pcg32::from_rng(&mut rand::rng());
24 | let mut buf = [0i32; 100];
25 | rng.fill(&mut buf);
26 | let x = black_box(&mut buf);
27 |
28 | b.iter(|| x.choose(&mut rng).unwrap());
29 | });
30 |
31 | let lens = [(1, 1000), (950, 1000), (10, 100), (90, 100)];
32 | for (amount, len) in lens {
33 | let name = format!("seq_slice_sample_{amount}_of_{len}");
34 | c.bench_function(name.as_str(), |b| {
35 | let mut rng = Pcg32::from_rng(&mut rand::rng());
36 | let mut buf = [0i32; 1000];
37 | rng.fill(&mut buf);
38 | let x = black_box(&buf[..len]);
39 |
40 | let mut results_buf = [0i32; 950];
41 | let y = black_box(&mut results_buf[..amount]);
42 | let amount = black_box(amount);
43 |
44 | b.iter(|| {
45 | // Collect full result to prevent unwanted shortcuts getting
46 | // first element (in case sample_indices returns an iterator).
47 | for (slot, sample) in y.iter_mut().zip(x.sample(&mut rng, amount)) {
48 | *slot = *sample;
49 | }
50 | y[amount - 1]
51 | })
52 | });
53 | }
54 |
55 | let lens = [(1, 1000), (950, 1000), (10, 100), (90, 100)];
56 | for (amount, len) in lens {
57 | let name = format!("seq_slice_sample_weighted_{amount}_of_{len}");
58 | c.bench_function(name.as_str(), |b| {
59 | let mut rng = Pcg32::from_rng(&mut rand::rng());
60 | let mut buf = [0i32; 1000];
61 | rng.fill(&mut buf);
62 | let x = black_box(&buf[..len]);
63 |
64 | let mut results_buf = [0i32; 950];
65 | let y = black_box(&mut results_buf[..amount]);
66 | let amount = black_box(amount);
67 |
68 | b.iter(|| {
69 | // Collect full result to prevent unwanted shortcuts getting
70 | // first element (in case sample_indices returns an iterator).
71 | let samples_iter = x.sample_weighted(&mut rng, amount, |_| 1.0).unwrap();
72 | for (slot, sample) in y.iter_mut().zip(samples_iter) {
73 | *slot = *sample;
74 | }
75 | y[amount - 1]
76 | })
77 | });
78 | }
79 |
80 | c.bench_function("seq_iter_sample_10_of_100", |b| {
81 | let mut rng = Pcg32::from_rng(&mut rand::rng());
82 | let mut buf = [0i32; 100];
83 | rng.fill(&mut buf);
84 | let x = black_box(&buf);
85 | b.iter(|| x.iter().cloned().sample(&mut rng, 10))
86 | });
87 |
88 | c.bench_function("seq_iter_sample_fill_10_of_100", |b| {
89 | let mut rng = Pcg32::from_rng(&mut rand::rng());
90 | let mut buf = [0i32; 100];
91 | rng.fill(&mut buf);
92 | let x = black_box(&buf);
93 | let mut buf = [0; 10];
94 | b.iter(|| x.iter().cloned().sample_fill(&mut rng, &mut buf))
95 | });
96 |
97 | bench_rng::(c, "ChaCha20");
98 | bench_rng::(c, "Pcg32");
99 | bench_rng::(c, "Pcg64");
100 | }
101 |
102 | fn bench_rng(c: &mut Criterion, rng_name: &'static str) {
103 | for length in [1, 2, 3, 10, 100, 1000].map(black_box) {
104 | let name = format!("choose_size-hinted_from_{length}_{rng_name}");
105 | c.bench_function(name.as_str(), |b| {
106 | let mut rng = Rng::seed_from_u64(123);
107 | b.iter(|| choose_size_hinted(length, &mut rng))
108 | });
109 |
110 | let name = format!("choose_stable_from_{length}_{rng_name}");
111 | c.bench_function(name.as_str(), |b| {
112 | let mut rng = Rng::seed_from_u64(123);
113 | b.iter(|| choose_stable(length, &mut rng))
114 | });
115 |
116 | let name = format!("choose_unhinted_from_{length}_{rng_name}");
117 | c.bench_function(name.as_str(), |b| {
118 | let mut rng = Rng::seed_from_u64(123);
119 | b.iter(|| choose_unhinted(length, &mut rng))
120 | });
121 |
122 | let name = format!("choose_windowed_from_{length}_{rng_name}");
123 | c.bench_function(name.as_str(), |b| {
124 | let mut rng = Rng::seed_from_u64(123);
125 | b.iter(|| choose_windowed(length, 7, &mut rng))
126 | });
127 | }
128 | }
129 |
130 | fn choose_size_hinted(max: usize, rng: &mut R) -> Option {
131 | let iterator = 0..max;
132 | iterator.choose(rng)
133 | }
134 |
135 | fn choose_stable(max: usize, rng: &mut R) -> Option {
136 | let iterator = 0..max;
137 | iterator.choose_stable(rng)
138 | }
139 |
140 | fn choose_unhinted(max: usize, rng: &mut R) -> Option {
141 | let iterator = UnhintedIterator { iter: (0..max) };
142 | iterator.choose(rng)
143 | }
144 |
145 | fn choose_windowed(max: usize, window_size: usize, rng: &mut R) -> Option {
146 | let iterator = WindowHintedIterator {
147 | iter: (0..max),
148 | window_size,
149 | };
150 | iterator.choose(rng)
151 | }
152 |
153 | #[derive(Clone)]
154 | struct UnhintedIterator {
155 | iter: I,
156 | }
157 | impl Iterator for UnhintedIterator {
158 | type Item = I::Item;
159 |
160 | fn next(&mut self) -> Option {
161 | self.iter.next()
162 | }
163 | }
164 |
165 | #[derive(Clone)]
166 | struct WindowHintedIterator {
167 | iter: I,
168 | window_size: usize,
169 | }
170 | impl Iterator for WindowHintedIterator {
171 | type Item = I::Item;
172 |
173 | fn next(&mut self) -> Option {
174 | self.iter.next()
175 | }
176 |
177 | fn size_hint(&self) -> (usize, Option) {
178 | (core::cmp::min(self.iter.len(), self.window_size), None)
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/rand_pcg/src/pcg128cm.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2021 Developers of the Rand project.
2 | // Copyright 2017 Paul Dicker.
3 | // Copyright 2014-2017, 2019 Melissa O'Neill and PCG Project contributors
4 | //
5 | // Licensed under the Apache License, Version 2.0 or the MIT license
7 | // , at your
8 | // option. This file may not be copied, modified, or distributed
9 | // except according to those terms.
10 |
11 | //! PCG random number generators
12 |
13 | // This is the cheap multiplier used by PCG for 128-bit state.
14 | const MULTIPLIER: u64 = 15750249268501108917;
15 |
16 | use core::fmt;
17 | use rand_core::{RngCore, SeedableRng, le};
18 | #[cfg(feature = "serde")]
19 | use serde::{Deserialize, Serialize};
20 |
21 | /// A PCG random number generator (CM DXSM 128/64 (LCG) variant).
22 | ///
23 | /// Permuted Congruential Generator with 128-bit state, internal Linear
24 | /// Congruential Generator, and 64-bit output via "double xorshift multiply"
25 | /// output function.
26 | ///
27 | /// This is a 128-bit LCG with explicitly chosen stream with the PCG-DXSM
28 | /// output function. This corresponds to `pcg_engines::cm_setseq_dxsm_128_64`
29 | /// from pcg_cpp and `PCG64DXSM` from NumPy.
30 | ///
31 | /// Despite the name, this implementation uses 32 bytes (256 bit) space
32 | /// comprising 128 bits of state and 128 bits stream selector. These are both
33 | /// set by `SeedableRng`, using a 256-bit seed.
34 | ///
35 | /// Note that while two generators with different stream parameter may be
36 | /// closely correlated, this is [mitigated][upgrading-pcg64] by the DXSM output function.
37 | ///
38 | /// [upgrading-pcg64]: https://numpy.org/doc/stable/reference/random/upgrading-pcg64.html
39 | #[derive(Clone, PartialEq, Eq)]
40 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
41 | pub struct Lcg128CmDxsm64 {
42 | state: u128,
43 | increment: u128,
44 | }
45 |
46 | /// [`Lcg128CmDxsm64`] is also known as `PCG64DXSM`.
47 | pub type Pcg64Dxsm = Lcg128CmDxsm64;
48 |
49 | impl Lcg128CmDxsm64 {
50 | /// Multi-step advance functions (jump-ahead, jump-back)
51 | ///
52 | /// The method used here is based on Brown, "Random Number Generation
53 | /// with Arbitrary Stride,", Transactions of the American Nuclear
54 | /// Society (Nov. 1994). The algorithm is very similar to fast
55 | /// exponentiation.
56 | ///
57 | /// Even though delta is an unsigned integer, we can pass a
58 | /// signed integer to go backwards, it just goes "the long way round".
59 | ///
60 | /// Using this function is equivalent to calling `next_64()` `delta`
61 | /// number of times.
62 | #[inline]
63 | pub fn advance(&mut self, delta: u128) {
64 | let mut acc_mult: u128 = 1;
65 | let mut acc_plus: u128 = 0;
66 | let mut cur_mult = MULTIPLIER as u128;
67 | let mut cur_plus = self.increment;
68 | let mut mdelta = delta;
69 |
70 | while mdelta > 0 {
71 | if (mdelta & 1) != 0 {
72 | acc_mult = acc_mult.wrapping_mul(cur_mult);
73 | acc_plus = acc_plus.wrapping_mul(cur_mult).wrapping_add(cur_plus);
74 | }
75 | cur_plus = cur_mult.wrapping_add(1).wrapping_mul(cur_plus);
76 | cur_mult = cur_mult.wrapping_mul(cur_mult);
77 | mdelta /= 2;
78 | }
79 | self.state = acc_mult.wrapping_mul(self.state).wrapping_add(acc_plus);
80 | }
81 |
82 | /// Construct an instance compatible with PCG seed and stream.
83 | ///
84 | /// Note that the highest bit of the `stream` parameter is discarded
85 | /// to simplify upholding internal invariants.
86 | ///
87 | /// Note that while two generators with different stream parameter may be
88 | /// closely correlated, this is [mitigated][upgrading-pcg64] by the DXSM output function.
89 | ///
90 | /// PCG specifies the following default values for both parameters:
91 | ///
92 | /// - `state = 0xcafef00dd15ea5e5`
93 | /// - `stream = 0xa02bdbf7bb3c0a7ac28fa16a64abf96`
94 | ///
95 | /// [upgrading-pcg64]: https://numpy.org/doc/stable/reference/random/upgrading-pcg64.html
96 | pub fn new(state: u128, stream: u128) -> Self {
97 | // The increment must be odd, hence we discard one bit:
98 | let increment = (stream << 1) | 1;
99 | Self::from_state_incr(state, increment)
100 | }
101 |
102 | #[inline]
103 | fn from_state_incr(state: u128, increment: u128) -> Self {
104 | let mut pcg = Self { state, increment };
105 | // Move away from initial value:
106 | pcg.state = pcg.state.wrapping_add(pcg.increment);
107 | pcg.step();
108 | pcg
109 | }
110 |
111 | #[inline(always)]
112 | fn step(&mut self) {
113 | // prepare the LCG for the next round
114 | self.state = self
115 | .state
116 | .wrapping_mul(MULTIPLIER as u128)
117 | .wrapping_add(self.increment);
118 | }
119 | }
120 |
121 | // Custom Debug implementation that does not expose the internal state
122 | impl fmt::Debug for Lcg128CmDxsm64 {
123 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124 | write!(f, "Lcg128CmDxsm64 {{}}")
125 | }
126 | }
127 |
128 | impl SeedableRng for Lcg128CmDxsm64 {
129 | type Seed = [u8; 32];
130 |
131 | /// We use a single 255-bit seed to initialise the state and select a stream.
132 | /// One `seed` bit (lowest bit of `seed[8]`) is ignored.
133 | fn from_seed(seed: Self::Seed) -> Self {
134 | let mut seed_u64 = [0u64; 4];
135 | le::read_u64_into(&seed, &mut seed_u64);
136 | let state = u128::from(seed_u64[0]) | (u128::from(seed_u64[1]) << 64);
137 | let incr = u128::from(seed_u64[2]) | (u128::from(seed_u64[3]) << 64);
138 |
139 | // The increment must be odd, hence we discard one bit:
140 | Self::from_state_incr(state, incr | 1)
141 | }
142 | }
143 |
144 | impl RngCore for Lcg128CmDxsm64 {
145 | #[inline]
146 | fn next_u32(&mut self) -> u32 {
147 | self.next_u64() as u32
148 | }
149 |
150 | #[inline]
151 | fn next_u64(&mut self) -> u64 {
152 | let res = output_dxsm(self.state);
153 | self.step();
154 | res
155 | }
156 |
157 | #[inline]
158 | fn fill_bytes(&mut self, dest: &mut [u8]) {
159 | le::fill_bytes_via_next(self, dest)
160 | }
161 | }
162 |
163 | #[inline(always)]
164 | fn output_dxsm(state: u128) -> u64 {
165 | // See https://github.com/imneme/pcg-cpp/blob/ffd522e7188bef30a00c74dc7eb9de5faff90092/include/pcg_random.hpp#L1016
166 | // for a short discussion of the construction and its original implementation.
167 | let mut hi = (state >> 64) as u64;
168 | let mut lo = state as u64;
169 |
170 | lo |= 1;
171 | hi ^= hi >> 32;
172 | hi = hi.wrapping_mul(MULTIPLIER);
173 | hi ^= hi >> 48;
174 | hi = hi.wrapping_mul(lo);
175 |
176 | hi
177 | }
178 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Main tests
2 |
3 | on:
4 | push:
5 | branches: [ master, '0.[0-9]+' ]
6 | paths-ignore:
7 | - "**.md"
8 | - "benches/**"
9 | pull_request:
10 | branches: [ master, '0.[0-9]+' ]
11 | paths-ignore:
12 | - "**.md"
13 | - "benches/**"
14 | schedule:
15 | - cron: '0 0 * * SUN'
16 |
17 | permissions:
18 | contents: read # to fetch code (actions/checkout)
19 |
20 | jobs:
21 | clippy-fmt:
22 | name: Check Clippy and rustfmt
23 | runs-on: ubuntu-latest
24 | steps:
25 | - uses: actions/checkout@v4
26 | - uses: dtolnay/rust-toolchain@master
27 | with:
28 | toolchain: stable
29 | components: clippy, rustfmt
30 | - name: Check Clippy
31 | run: cargo clippy --workspace -- -D warnings
32 | - name: Check rustfmt
33 | run: cargo fmt --all -- --check
34 |
35 | check-doc:
36 | name: Check doc
37 | runs-on: ubuntu-latest
38 | env:
39 | RUSTDOCFLAGS: "-Dwarnings --cfg docsrs -Zunstable-options --generate-link-to-definition"
40 | steps:
41 | - uses: actions/checkout@v4
42 | - name: Install toolchain
43 | uses: dtolnay/rust-toolchain@master
44 | with:
45 | toolchain: nightly
46 | - name: rand
47 | run: cargo doc --all-features --no-deps
48 | - name: rand_chacha
49 | run: cargo doc --all-features --package rand_chacha --no-deps
50 | - name: rand_pcg
51 | run: cargo doc --all-features --package rand_pcg --no-deps
52 |
53 | test:
54 | runs-on: ${{ matrix.os }}
55 | strategy:
56 | fail-fast: false
57 | matrix:
58 | include:
59 | - os: ubuntu-latest
60 | target: x86_64-unknown-linux-gnu
61 | toolchain: stable
62 | - os: macos-latest
63 | target: x86_64-apple-darwin
64 | toolchain: stable
65 | # TODO: also aarch64 / M1
66 | - os: windows-latest
67 | target: x86_64-pc-windows-gnu
68 | toolchain: stable
69 | - os: windows-latest
70 | target: x86_64-pc-windows-msvc
71 | toolchain: beta
72 | # Test both windows-gnu and windows-msvc; use beta rust on one
73 | - os: ubuntu-latest
74 | target: x86_64-unknown-linux-gnu
75 | variant: MSRV
76 | toolchain: 1.85.0
77 | - os: ubuntu-latest
78 | deps: sudo apt-get update ; sudo apt install gcc-multilib
79 | target: i686-unknown-linux-gnu
80 | toolchain: nightly
81 | - os: ubuntu-latest
82 | target: x86_64-unknown-linux-gnu
83 | toolchain: nightly
84 | variant: minimal_versions
85 |
86 | steps:
87 | - uses: actions/checkout@v4
88 | - name: Not MSRV
89 | if: ${{ matrix.variant != 'MSRV' }}
90 | run: cargo generate-lockfile --ignore-rust-version
91 | - name: Install toolchain
92 | uses: dtolnay/rust-toolchain@master
93 | with:
94 | target: ${{ matrix.target }}
95 | toolchain: ${{ matrix.toolchain }}
96 | - run: ${{ matrix.deps }}
97 | - name: Maybe minimal versions
98 | if: ${{ matrix.variant == 'minimal_versions' }}
99 | run: |
100 | cargo generate-lockfile -Z minimal-versions
101 | - name: Maybe nightly
102 | if: ${{ matrix.toolchain == 'nightly' }}
103 | run: |
104 | cargo test --target ${{ matrix.target }} --features=nightly
105 | cargo test --target ${{ matrix.target }} --all-features
106 | cargo test --target ${{ matrix.target }} --lib --tests --no-default-features
107 | - name: Test rand
108 | run: |
109 | cargo test --target ${{ matrix.target }} --lib --tests --no-default-features
110 | cargo build --target ${{ matrix.target }} --no-default-features --features alloc,os_rng,small_rng,unbiased
111 | cargo test --target ${{ matrix.target }} --lib --tests --no-default-features --features=alloc,os_rng,small_rng
112 | cargo test --target ${{ matrix.target }} --examples
113 | - name: Test rand (all stable features)
114 | run: |
115 | cargo test --target ${{ matrix.target }} --features=serde,log,small_rng
116 | - name: Test rand_pcg
117 | run: cargo test --target ${{ matrix.target }} --manifest-path rand_pcg/Cargo.toml --features=serde
118 | - name: Test rand_chacha
119 | run: cargo test --target ${{ matrix.target }} --manifest-path rand_chacha/Cargo.toml --features=serde
120 |
121 | test-cross:
122 | runs-on: ${{ matrix.os }}
123 | strategy:
124 | fail-fast: false
125 | matrix:
126 | include:
127 | - os: ubuntu-latest
128 | target: powerpc-unknown-linux-gnu
129 | toolchain: stable
130 |
131 | steps:
132 | - uses: actions/checkout@v4
133 | - name: Install toolchain
134 | uses: dtolnay/rust-toolchain@master
135 | with:
136 | target: ${{ matrix.target }}
137 | toolchain: ${{ matrix.toolchain }}
138 | - name: Cache cargo plugins
139 | uses: actions/cache@v4
140 | with:
141 | path: ~/.cargo/bin/
142 | key: ${{ runner.os }}-cargo-plugins
143 | - name: Install cross
144 | run: cargo install cross || true
145 | - name: Test
146 | run: |
147 | # all stable features:
148 | cross test --no-fail-fast --target ${{ matrix.target }} --features=serde,log,small_rng
149 | cross test --no-fail-fast --target ${{ matrix.target }} --examples
150 | cross test --no-fail-fast --target ${{ matrix.target }} --manifest-path rand_pcg/Cargo.toml --features=serde
151 | cross test --no-fail-fast --target ${{ matrix.target }} --manifest-path rand_chacha/Cargo.toml
152 |
153 | test-miri:
154 | runs-on: ubuntu-latest
155 | steps:
156 | - uses: actions/checkout@v4
157 | - name: Install toolchain
158 | run: |
159 | rustup toolchain install nightly --component miri
160 | rustup override set nightly
161 | cargo miri setup
162 | - name: Test rand
163 | run: |
164 | cargo miri test --no-default-features --lib --tests
165 | cargo miri test --features=log,small_rng
166 | cargo miri test --manifest-path rand_pcg/Cargo.toml --features=serde
167 | cargo miri test --manifest-path rand_chacha/Cargo.toml --no-default-features
168 |
169 | test-no-std:
170 | runs-on: ubuntu-latest
171 | steps:
172 | - uses: actions/checkout@v4
173 | - name: Install toolchain
174 | uses: dtolnay/rust-toolchain@nightly
175 | with:
176 | target: thumbv6m-none-eabi
177 | - name: Build top-level only
178 | run: cargo build --target=thumbv6m-none-eabi --no-default-features
179 |
180 | test-ios:
181 | runs-on: macos-latest
182 | steps:
183 | - uses: actions/checkout@v4
184 | - name: Install toolchain
185 | uses: dtolnay/rust-toolchain@nightly
186 | with:
187 | target: aarch64-apple-ios
188 | - name: Build top-level only
189 | run: cargo build --target=aarch64-apple-ios
190 |
--------------------------------------------------------------------------------
/src/seq/coin_flipper.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018-2023 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use crate::RngCore;
10 |
11 | pub(crate) struct CoinFlipper {
12 | pub rng: R,
13 | chunk: u32, // TODO(opt): this should depend on RNG word size
14 | chunk_remaining: u32,
15 | }
16 |
17 | impl CoinFlipper {
18 | pub fn new(rng: R) -> Self {
19 | Self {
20 | rng,
21 | chunk: 0,
22 | chunk_remaining: 0,
23 | }
24 | }
25 |
26 | #[inline]
27 | /// Returns true with a probability of 1 / d
28 | /// Uses an expected two bits of randomness
29 | /// Panics if d == 0
30 | pub fn random_ratio_one_over(&mut self, d: usize) -> bool {
31 | debug_assert_ne!(d, 0);
32 | // This uses the same logic as `random_ratio` but is optimized for the case that
33 | // the starting numerator is one (which it always is for `Sequence::Choose()`)
34 |
35 | // In this case (but not `random_ratio`), this way of calculating c is always accurate
36 | let c = (usize::BITS - 1 - d.leading_zeros()).min(32);
37 |
38 | if self.flip_c_heads(c) {
39 | let numerator = 1 << c;
40 | self.random_ratio(numerator, d)
41 | } else {
42 | false
43 | }
44 | }
45 |
46 | #[inline]
47 | /// Returns true with a probability of n / d
48 | /// Uses an expected two bits of randomness
49 | fn random_ratio(&mut self, mut n: usize, d: usize) -> bool {
50 | // Explanation:
51 | // We are trying to return true with a probability of n / d
52 | // If n >= d, we can just return true
53 | // Otherwise there are two possibilities 2n < d and 2n >= d
54 | // In either case we flip a coin.
55 | // If 2n < d
56 | // If it comes up tails, return false
57 | // If it comes up heads, double n and start again
58 | // This is fair because (0.5 * 0) + (0.5 * 2n / d) = n / d and 2n is less than d
59 | // (if 2n was greater than d we would effectively round it down to 1
60 | // by returning true)
61 | // If 2n >= d
62 | // If it comes up tails, set n to 2n - d and start again
63 | // If it comes up heads, return true
64 | // This is fair because (0.5 * 1) + (0.5 * (2n - d) / d) = n / d
65 | // Note that if 2n = d and the coin comes up tails, n will be set to 0
66 | // before restarting which is equivalent to returning false.
67 |
68 | // As a performance optimization we can flip multiple coins at once
69 | // This is efficient because we can use the `lzcnt` intrinsic
70 | // We can check up to 32 flips at once but we only receive one bit of information
71 | // - all heads or at least one tail.
72 |
73 | // Let c be the number of coins to flip. 1 <= c <= 32
74 | // If 2n < d, n * 2^c < d
75 | // If the result is all heads, then set n to n * 2^c
76 | // If there was at least one tail, return false
77 | // If 2n >= d, the order of results matters so we flip one coin at a time so c = 1
78 | // Ideally, c will be as high as possible within these constraints
79 |
80 | while n < d {
81 | // Find a good value for c by counting leading zeros
82 | // This will either give the highest possible c, or 1 less than that
83 | let c = n
84 | .leading_zeros()
85 | .saturating_sub(d.leading_zeros() + 1)
86 | .clamp(1, 32);
87 |
88 | if self.flip_c_heads(c) {
89 | // All heads
90 | // Set n to n * 2^c
91 | // If 2n >= d, the while loop will exit and we will return `true`
92 | // If n * 2^c > `usize::MAX` we always return `true` anyway
93 | n = n.saturating_mul(2_usize.pow(c));
94 | } else {
95 | // At least one tail
96 | if c == 1 {
97 | // Calculate 2n - d.
98 | // We need to use wrapping as 2n might be greater than `usize::MAX`
99 | let next_n = n.wrapping_add(n).wrapping_sub(d);
100 | if next_n == 0 || next_n > n {
101 | // This will happen if 2n < d
102 | return false;
103 | }
104 | n = next_n;
105 | } else {
106 | // c > 1 so 2n < d so we can return false
107 | return false;
108 | }
109 | }
110 | }
111 | true
112 | }
113 |
114 | /// If the next `c` bits of randomness all represent heads, consume them, return true
115 | /// Otherwise return false and consume the number of heads plus one.
116 | /// Generates new bits of randomness when necessary (in 32 bit chunks)
117 | /// Has a 1 in 2 to the `c` chance of returning true
118 | /// `c` must be less than or equal to 32
119 | fn flip_c_heads(&mut self, mut c: u32) -> bool {
120 | debug_assert!(c <= 32);
121 | // Note that zeros on the left of the chunk represent heads.
122 | // It needs to be this way round because zeros are filled in when left shifting
123 | loop {
124 | let zeros = self.chunk.leading_zeros();
125 |
126 | if zeros < c {
127 | // The happy path - we found a 1 and can return false
128 | // Note that because a 1 bit was detected,
129 | // We cannot have run out of random bits so we don't need to check
130 |
131 | // First consume all of the bits read
132 | // Using shl seems to give worse performance for size-hinted iterators
133 | self.chunk = self.chunk.wrapping_shl(zeros + 1);
134 |
135 | self.chunk_remaining = self.chunk_remaining.saturating_sub(zeros + 1);
136 | return false;
137 | } else {
138 | // The number of zeros is larger than `c`
139 | // There are two possibilities
140 | if let Some(new_remaining) = self.chunk_remaining.checked_sub(c) {
141 | // Those zeroes were all part of our random chunk,
142 | // throw away `c` bits of randomness and return true
143 | self.chunk_remaining = new_remaining;
144 | self.chunk <<= c;
145 | return true;
146 | } else {
147 | // Some of those zeroes were part of the random chunk
148 | // and some were part of the space behind it
149 | // We need to take into account only the zeroes that were random
150 | c -= self.chunk_remaining;
151 |
152 | // Generate a new chunk
153 | self.chunk = self.rng.next_u32();
154 | self.chunk_remaining = 32;
155 | // Go back to start of loop
156 | }
157 | }
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/rngs/thread.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! Thread-local random number generator
10 |
11 | use core::cell::UnsafeCell;
12 | use std::fmt;
13 | use std::rc::Rc;
14 | use std::thread_local;
15 |
16 | use super::{OsError, OsRng, ReseedingRng, std::Core};
17 | use rand_core::{CryptoRng, RngCore};
18 |
19 | // Rationale for using `UnsafeCell` in `ThreadRng`:
20 | //
21 | // Previously we used a `RefCell`, with an overhead of ~15%. There will only
22 | // ever be one mutable reference to the interior of the `UnsafeCell`, because
23 | // we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
24 | // single thread (which is the definition of `ThreadRng`), there will only ever
25 | // be one of these methods active at a time.
26 | //
27 | // A possible scenario where there could be multiple mutable references is if
28 | // `ThreadRng` is used inside `next_u32` and co. But the implementation is
29 | // completely under our control. We just have to ensure none of them use
30 | // `ThreadRng` internally, which is nonsensical anyway. We should also never run
31 | // `ThreadRng` in destructors of its implementation, which is also nonsensical.
32 |
33 | // Number of generated bytes after which to reseed `ThreadRng`.
34 | // According to benchmarks, reseeding has a noticeable impact with thresholds
35 | // of 32 kB and less. We choose 64 kB to avoid significant overhead.
36 | const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
37 |
38 | /// A reference to the thread-local generator
39 | ///
40 | /// This type is a reference to a lazily-initialized thread-local generator.
41 | /// An instance can be obtained via [`rand::rng()`][crate::rng()] or via
42 | /// [`ThreadRng::default()`].
43 | /// The handle cannot be passed between threads (is not `Send` or `Sync`).
44 | ///
45 | /// # Security
46 | ///
47 | /// Security must be considered relative to a threat model and validation
48 | /// requirements. The Rand project can provide no guarantee of fitness for
49 | /// purpose. The design criteria for `ThreadRng` are as follows:
50 | ///
51 | /// - Automatic seeding via [`OsRng`] and periodically thereafter (see
52 | /// ([`ReseedingRng`] documentation). Limitation: there is no automatic
53 | /// reseeding on process fork (see [below](#fork)).
54 | /// - A rigorusly analyzed, unpredictable (cryptographic) pseudo-random generator
55 | /// (see [the book on security](https://rust-random.github.io/book/guide-rngs.html#security)).
56 | /// The currently selected algorithm is ChaCha (12-rounds).
57 | /// See also [`StdRng`] documentation.
58 | /// - Not to leak internal state through [`Debug`] or serialization
59 | /// implementations.
60 | /// - No further protections exist to in-memory state. In particular, the
61 | /// implementation is not required to zero memory on exit (of the process or
62 | /// thread). (This may change in the future.)
63 | /// - Be fast enough for general-purpose usage. Note in particular that
64 | /// `ThreadRng` is designed to be a "fast, reasonably secure generator"
65 | /// (where "reasonably secure" implies the above criteria).
66 | ///
67 | /// We leave it to the user to determine whether this generator meets their
68 | /// security requirements. For an alternative, see [`OsRng`].
69 | ///
70 | /// # Fork
71 | ///
72 | /// `ThreadRng` is not automatically reseeded on fork. It is recommended to
73 | /// explicitly call [`ThreadRng::reseed`] immediately after a fork, for example:
74 | /// ```ignore
75 | /// fn do_fork() {
76 | /// let pid = unsafe { libc::fork() };
77 | /// if pid == 0 {
78 | /// // Reseed ThreadRng in child processes:
79 | /// rand::rng().reseed();
80 | /// }
81 | /// }
82 | /// ```
83 | ///
84 | /// Methods on `ThreadRng` are not reentrant-safe and thus should not be called
85 | /// from an interrupt (e.g. a fork handler) unless it can be guaranteed that no
86 | /// other method on the same `ThreadRng` is currently executing.
87 | ///
88 | /// [`ReseedingRng`]: crate::rngs::ReseedingRng
89 | /// [`StdRng`]: crate::rngs::StdRng
90 | #[derive(Clone)]
91 | pub struct ThreadRng {
92 | // Rc is explicitly !Send and !Sync
93 | rng: Rc>>,
94 | }
95 |
96 | impl ThreadRng {
97 | /// Immediately reseed the generator
98 | ///
99 | /// This discards any remaining random data in the cache.
100 | pub fn reseed(&mut self) -> Result<(), OsError> {
101 | // SAFETY: We must make sure to stop using `rng` before anyone else
102 | // creates another mutable reference
103 | let rng = unsafe { &mut *self.rng.get() };
104 | rng.reseed()
105 | }
106 | }
107 |
108 | /// Debug implementation does not leak internal state
109 | impl fmt::Debug for ThreadRng {
110 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
111 | write!(fmt, "ThreadRng {{ .. }}")
112 | }
113 | }
114 |
115 | thread_local!(
116 | // We require Rc<..> to avoid premature freeing when ThreadRng is used
117 | // within thread-local destructors. See #968.
118 | static THREAD_RNG_KEY: Rc>> = {
119 | let rng = ReseedingRng::new(THREAD_RNG_RESEED_THRESHOLD,
120 | OsRng).unwrap_or_else(|err|
121 | panic!("could not initialize ThreadRng: {}", err));
122 | Rc::new(UnsafeCell::new(rng))
123 | }
124 | );
125 |
126 | /// Access a fast, pre-initialized generator
127 | ///
128 | /// This is a handle to the local [`ThreadRng`].
129 | ///
130 | /// See also [`crate::rngs`] for alternatives.
131 | ///
132 | /// # Example
133 | ///
134 | /// ```
135 | /// use rand::prelude::*;
136 | ///
137 | /// # fn main() {
138 | ///
139 | /// let mut numbers = [1, 2, 3, 4, 5];
140 | /// numbers.shuffle(&mut rand::rng());
141 | /// println!("Numbers: {numbers:?}");
142 | ///
143 | /// // Using a local binding avoids an initialization-check on each usage:
144 | /// let mut rng = rand::rng();
145 | ///
146 | /// println!("True or false: {}", rng.random::());
147 | /// println!("A simulated die roll: {}", rng.random_range(1..=6));
148 | /// # }
149 | /// ```
150 | ///
151 | /// # Security
152 | ///
153 | /// Refer to [`ThreadRng#Security`].
154 | pub fn rng() -> ThreadRng {
155 | let rng = THREAD_RNG_KEY.with(|t| t.clone());
156 | ThreadRng { rng }
157 | }
158 |
159 | impl Default for ThreadRng {
160 | fn default() -> ThreadRng {
161 | rng()
162 | }
163 | }
164 |
165 | impl RngCore for ThreadRng {
166 | #[inline(always)]
167 | fn next_u32(&mut self) -> u32 {
168 | // SAFETY: We must make sure to stop using `rng` before anyone else
169 | // creates another mutable reference
170 | let rng = unsafe { &mut *self.rng.get() };
171 | rng.next_u32()
172 | }
173 |
174 | #[inline(always)]
175 | fn next_u64(&mut self) -> u64 {
176 | // SAFETY: We must make sure to stop using `rng` before anyone else
177 | // creates another mutable reference
178 | let rng = unsafe { &mut *self.rng.get() };
179 | rng.next_u64()
180 | }
181 |
182 | #[inline(always)]
183 | fn fill_bytes(&mut self, dest: &mut [u8]) {
184 | // SAFETY: We must make sure to stop using `rng` before anyone else
185 | // creates another mutable reference
186 | let rng = unsafe { &mut *self.rng.get() };
187 | rng.fill_bytes(dest)
188 | }
189 | }
190 |
191 | impl CryptoRng for ThreadRng {}
192 |
193 | #[cfg(test)]
194 | mod test {
195 | #[test]
196 | fn test_thread_rng() {
197 | use crate::Rng;
198 | let mut r = crate::rng();
199 | r.random::();
200 | assert_eq!(r.random_range(0..1), 0);
201 | }
202 |
203 | #[test]
204 | fn test_debug_output() {
205 | // We don't care about the exact output here, but it must not include
206 | // private CSPRNG state or the cache stored by BlockRng!
207 | assert_eq!(std::format!("{:?}", crate::rng()), "ThreadRng { .. }");
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/benches/benches/generators.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | use core::time::Duration;
10 | use criterion::measurement::WallTime;
11 | use criterion::{BenchmarkGroup, Criterion, black_box, criterion_group, criterion_main};
12 | use rand::prelude::*;
13 | use rand::rngs::OsRng;
14 | use rand::rngs::ReseedingRng;
15 | use rand_chacha::rand_core::UnwrapErr;
16 | use rand_chacha::{ChaCha8Rng, ChaCha12Rng, ChaCha20Core, ChaCha20Rng};
17 | use rand_pcg::{Pcg32, Pcg64, Pcg64Dxsm, Pcg64Mcg};
18 |
19 | criterion_group!(
20 | name = benches;
21 | config = Criterion::default();
22 | targets = random_bytes, random_u32, random_u64, init_gen, init_from_u64, init_from_seed, reseeding_bytes
23 | );
24 | criterion_main!(benches);
25 |
26 | pub fn random_bytes(c: &mut Criterion) {
27 | let mut g = c.benchmark_group("random_bytes");
28 | g.warm_up_time(Duration::from_millis(500));
29 | g.measurement_time(Duration::from_millis(1000));
30 | g.throughput(criterion::Throughput::Bytes(1024));
31 |
32 | fn bench(g: &mut BenchmarkGroup, name: &str, mut rng: impl Rng) {
33 | g.bench_function(name, |b| {
34 | let mut buf = [0u8; 1024];
35 | b.iter(|| {
36 | rng.fill_bytes(&mut buf);
37 | black_box(buf);
38 | });
39 | });
40 | }
41 |
42 | bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng()));
43 | bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng()));
44 | bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng()));
45 | bench(&mut g, "pcg64dxsm", Pcg64Dxsm::from_rng(&mut rand::rng()));
46 | bench(&mut g, "chacha8", ChaCha8Rng::from_rng(&mut rand::rng()));
47 | bench(&mut g, "chacha12", ChaCha12Rng::from_rng(&mut rand::rng()));
48 | bench(&mut g, "chacha20", ChaCha20Rng::from_rng(&mut rand::rng()));
49 | bench(&mut g, "std", StdRng::from_rng(&mut rand::rng()));
50 | bench(&mut g, "small", SmallRng::from_rng(&mut rand::rng()));
51 | bench(&mut g, "os", UnwrapErr(OsRng));
52 | bench(&mut g, "thread", rand::rng());
53 |
54 | g.finish()
55 | }
56 |
57 | pub fn random_u32(c: &mut Criterion) {
58 | let mut g = c.benchmark_group("random_u32");
59 | g.sample_size(1000);
60 | g.warm_up_time(Duration::from_millis(500));
61 | g.measurement_time(Duration::from_millis(1000));
62 | g.throughput(criterion::Throughput::Bytes(4));
63 |
64 | fn bench(g: &mut BenchmarkGroup, name: &str, mut rng: impl Rng) {
65 | g.bench_function(name, |b| {
66 | b.iter(|| rng.random::());
67 | });
68 | }
69 |
70 | bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng()));
71 | bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng()));
72 | bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng()));
73 | bench(&mut g, "pcg64dxsm", Pcg64Dxsm::from_rng(&mut rand::rng()));
74 | bench(&mut g, "chacha8", ChaCha8Rng::from_rng(&mut rand::rng()));
75 | bench(&mut g, "chacha12", ChaCha12Rng::from_rng(&mut rand::rng()));
76 | bench(&mut g, "chacha20", ChaCha20Rng::from_rng(&mut rand::rng()));
77 | bench(&mut g, "std", StdRng::from_rng(&mut rand::rng()));
78 | bench(&mut g, "small", SmallRng::from_rng(&mut rand::rng()));
79 | bench(&mut g, "os", UnwrapErr(OsRng));
80 | bench(&mut g, "thread", rand::rng());
81 |
82 | g.finish()
83 | }
84 |
85 | pub fn random_u64(c: &mut Criterion) {
86 | let mut g = c.benchmark_group("random_u64");
87 | g.sample_size(1000);
88 | g.warm_up_time(Duration::from_millis(500));
89 | g.measurement_time(Duration::from_millis(1000));
90 | g.throughput(criterion::Throughput::Bytes(8));
91 |
92 | fn bench(g: &mut BenchmarkGroup, name: &str, mut rng: impl Rng) {
93 | g.bench_function(name, |b| {
94 | b.iter(|| rng.random::());
95 | });
96 | }
97 |
98 | bench(&mut g, "pcg32", Pcg32::from_rng(&mut rand::rng()));
99 | bench(&mut g, "pcg64", Pcg64::from_rng(&mut rand::rng()));
100 | bench(&mut g, "pcg64mcg", Pcg64Mcg::from_rng(&mut rand::rng()));
101 | bench(&mut g, "pcg64dxsm", Pcg64Dxsm::from_rng(&mut rand::rng()));
102 | bench(&mut g, "chacha8", ChaCha8Rng::from_rng(&mut rand::rng()));
103 | bench(&mut g, "chacha12", ChaCha12Rng::from_rng(&mut rand::rng()));
104 | bench(&mut g, "chacha20", ChaCha20Rng::from_rng(&mut rand::rng()));
105 | bench(&mut g, "std", StdRng::from_rng(&mut rand::rng()));
106 | bench(&mut g, "small", SmallRng::from_rng(&mut rand::rng()));
107 | bench(&mut g, "os", UnwrapErr(OsRng));
108 | bench(&mut g, "thread", rand::rng());
109 |
110 | g.finish()
111 | }
112 |
113 | pub fn init_gen(c: &mut Criterion) {
114 | let mut g = c.benchmark_group("init_gen");
115 | g.warm_up_time(Duration::from_millis(500));
116 | g.measurement_time(Duration::from_millis(1000));
117 |
118 | fn bench(g: &mut BenchmarkGroup, name: &str) {
119 | g.bench_function(name, |b| {
120 | let mut rng = Pcg32::from_rng(&mut rand::rng());
121 | b.iter(|| R::from_rng(&mut rng));
122 | });
123 | }
124 |
125 | bench::(&mut g, "pcg32");
126 | bench::(&mut g, "pcg64");
127 | bench::(&mut g, "pcg64mcg");
128 | bench::(&mut g, "pcg64dxsm");
129 | bench::(&mut g, "chacha8");
130 | bench::(&mut g, "chacha12");
131 | bench::(&mut g, "chacha20");
132 | bench::(&mut g, "std");
133 | bench::(&mut g, "small");
134 |
135 | g.finish()
136 | }
137 |
138 | pub fn init_from_u64(c: &mut Criterion) {
139 | let mut g = c.benchmark_group("init_from_u64");
140 | g.warm_up_time(Duration::from_millis(500));
141 | g.measurement_time(Duration::from_millis(1000));
142 |
143 | fn bench(g: &mut BenchmarkGroup, name: &str) {
144 | g.bench_function(name, |b| {
145 | let mut rng = Pcg32::from_rng(&mut rand::rng());
146 | let seed = rng.random();
147 | b.iter(|| R::seed_from_u64(black_box(seed)));
148 | });
149 | }
150 |
151 | bench::(&mut g, "pcg32");
152 | bench::(&mut g, "pcg64");
153 | bench::(&mut g, "pcg64mcg");
154 | bench::(&mut g, "pcg64dxsm");
155 | bench::(&mut g, "chacha8");
156 | bench::(&mut g, "chacha12");
157 | bench::(&mut g, "chacha20");
158 | bench::(&mut g, "std");
159 | bench::(&mut g, "small");
160 |
161 | g.finish()
162 | }
163 |
164 | pub fn init_from_seed(c: &mut Criterion) {
165 | let mut g = c.benchmark_group("init_from_seed");
166 | g.warm_up_time(Duration::from_millis(500));
167 | g.measurement_time(Duration::from_millis(1000));
168 |
169 | fn bench(g: &mut BenchmarkGroup, name: &str)
170 | where
171 | rand::distr::StandardUniform: Distribution<::Seed>,
172 | {
173 | g.bench_function(name, |b| {
174 | let mut rng = Pcg32::from_rng(&mut rand::rng());
175 | let seed = rng.random();
176 | b.iter(|| R::from_seed(black_box(seed.clone())));
177 | });
178 | }
179 |
180 | bench::(&mut g, "pcg32");
181 | bench::(&mut g, "pcg64");
182 | bench::(&mut g, "pcg64mcg");
183 | bench::(&mut g, "pcg64dxsm");
184 | bench::(&mut g, "chacha8");
185 | bench::(&mut g, "chacha12");
186 | bench::(&mut g, "chacha20");
187 | bench::(&mut g, "std");
188 | bench::(&mut g, "small");
189 |
190 | g.finish()
191 | }
192 |
193 | pub fn reseeding_bytes(c: &mut Criterion) {
194 | let mut g = c.benchmark_group("reseeding_bytes");
195 | g.warm_up_time(Duration::from_millis(500));
196 | g.throughput(criterion::Throughput::Bytes(1024 * 1024));
197 |
198 | fn bench(g: &mut BenchmarkGroup, thresh: u64) {
199 | let name = format!("chacha20_{thresh}k");
200 | g.bench_function(name.as_str(), |b| {
201 | let mut rng = ReseedingRng::::new(thresh * 1024, OsRng).unwrap();
202 | let mut buf = [0u8; 1024 * 1024];
203 | b.iter(|| {
204 | rng.fill_bytes(&mut buf);
205 | black_box(&buf);
206 | });
207 | });
208 | }
209 |
210 | bench(&mut g, 4);
211 | bench(&mut g, 16);
212 | bench(&mut g, 32);
213 | bench(&mut g, 64);
214 | bench(&mut g, 256);
215 | bench(&mut g, 1024);
216 |
217 | g.finish()
218 | }
219 |
--------------------------------------------------------------------------------
/src/rngs/reseeding.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | // Copyright 2013 The Rust Project Developers.
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | //! A wrapper around another PRNG that reseeds it after it
11 | //! generates a certain number of random bytes.
12 |
13 | use core::mem::size_of_val;
14 |
15 | use rand_core::block::{BlockRng, BlockRngCore, CryptoBlockRng};
16 | use rand_core::{CryptoRng, RngCore, SeedableRng, TryCryptoRng, TryRngCore};
17 |
18 | /// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the
19 | /// ability to reseed it.
20 | ///
21 | /// `ReseedingRng` reseeds the underlying PRNG in the following cases:
22 | ///
23 | /// - On a manual call to [`reseed()`].
24 | /// - After the PRNG has generated a configurable number of random bytes.
25 | ///
26 | /// # When should reseeding after a fixed number of generated bytes be used?
27 | ///
28 | /// Reseeding after a fixed number of generated bytes is never strictly
29 | /// *necessary*. Cryptographic PRNGs don't have a limited number of bytes they
30 | /// can output, or at least not a limit reachable in any practical way. There is
31 | /// no such thing as 'running out of entropy'.
32 | ///
33 | /// Occasionally reseeding can be seen as some form of 'security in depth'. Even
34 | /// if in the future a cryptographic weakness is found in the CSPRNG being used,
35 | /// or a flaw in the implementation, occasionally reseeding should make
36 | /// exploiting it much more difficult or even impossible.
37 | ///
38 | /// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding
39 | /// after a fixed number of generated bytes.
40 | ///
41 | /// # Error handling
42 | ///
43 | /// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will
44 | /// never panic but try to handle the error intelligently through some
45 | /// combination of retrying and delaying reseeding until later.
46 | /// If handling the source error fails `ReseedingRng` will continue generating
47 | /// data from the wrapped PRNG without reseeding.
48 | ///
49 | /// Manually calling [`reseed()`] will not have this retry or delay logic, but
50 | /// reports the error.
51 | ///
52 | /// # Example
53 | ///
54 | /// ```
55 | /// use chacha20::ChaCha20Core; // Internal part of ChaChaRng that
56 | /// // implements BlockRngCore
57 | /// use rand::prelude::*;
58 | /// use rand::rngs::OsRng;
59 | /// use rand::rngs::ReseedingRng;
60 | ///
61 | /// let mut reseeding_rng = ReseedingRng::::new(0, OsRng).unwrap();
62 | ///
63 | /// println!("{}", reseeding_rng.random::());
64 | /// ```
65 | ///
66 | /// [`BlockRngCore`]: rand_core::block::BlockRngCore
67 | /// [`ReseedingRng::new`]: ReseedingRng::new
68 | /// [`reseed()`]: ReseedingRng::reseed
69 | #[derive(Debug)]
70 | pub struct ReseedingRng(BlockRng>)
71 | where
72 | R: BlockRngCore + SeedableRng,
73 | Rsdr: TryRngCore;
74 |
75 | impl ReseedingRng
76 | where
77 | R: BlockRngCore + SeedableRng,
78 | Rsdr: TryRngCore,
79 | {
80 | /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG
81 | /// to use as reseeder.
82 | ///
83 | /// `threshold` sets the number of generated bytes after which to reseed the
84 | /// PRNG. Set it to zero to never reseed based on the number of generated
85 | /// values.
86 | pub fn new(threshold: u64, reseeder: Rsdr) -> Result {
87 | Ok(ReseedingRng(BlockRng::new(ReseedingCore::new(
88 | threshold, reseeder,
89 | )?)))
90 | }
91 |
92 | /// Immediately reseed the generator
93 | ///
94 | /// This discards any remaining random data in the cache.
95 | pub fn reseed(&mut self) -> Result<(), Rsdr::Error> {
96 | self.0.reset();
97 | self.0.core.reseed()
98 | }
99 | }
100 |
101 | // TODO: this should be implemented for any type where the inner type
102 | // implements RngCore, but we can't specify that because ReseedingCore is private
103 | impl RngCore for ReseedingRng
104 | where
105 | R: BlockRngCore- + SeedableRng,
106 | Rsdr: TryRngCore,
107 | {
108 | #[inline(always)]
109 | fn next_u32(&mut self) -> u32 {
110 | self.0.next_u32()
111 | }
112 |
113 | #[inline(always)]
114 | fn next_u64(&mut self) -> u64 {
115 | self.0.next_u64()
116 | }
117 |
118 | fn fill_bytes(&mut self, dest: &mut [u8]) {
119 | self.0.fill_bytes(dest)
120 | }
121 | }
122 |
123 | impl CryptoRng for ReseedingRng
124 | where
125 | R: BlockRngCore
- + SeedableRng + CryptoBlockRng,
126 | Rsdr: TryCryptoRng,
127 | {
128 | }
129 |
130 | #[derive(Debug)]
131 | struct ReseedingCore {
132 | inner: R,
133 | reseeder: Rsdr,
134 | threshold: i64,
135 | bytes_until_reseed: i64,
136 | }
137 |
138 | impl BlockRngCore for ReseedingCore
139 | where
140 | R: BlockRngCore + SeedableRng,
141 | Rsdr: TryRngCore,
142 | {
143 | type Item = ::Item;
144 | type Results = ::Results;
145 |
146 | fn generate(&mut self, results: &mut Self::Results) {
147 | if self.bytes_until_reseed <= 0 {
148 | // We get better performance by not calling only `reseed` here
149 | // and continuing with the rest of the function, but by directly
150 | // returning from a non-inlined function.
151 | return self.reseed_and_generate(results);
152 | }
153 | let num_bytes = size_of_val(results.as_ref());
154 | self.bytes_until_reseed -= num_bytes as i64;
155 | self.inner.generate(results);
156 | }
157 | }
158 |
159 | impl ReseedingCore
160 | where
161 | R: BlockRngCore + SeedableRng,
162 | Rsdr: TryRngCore,
163 | {
164 | /// Create a new `ReseedingCore`.
165 | ///
166 | /// `threshold` is the maximum number of bytes produced by
167 | /// [`BlockRngCore::generate`] before attempting reseeding.
168 | fn new(threshold: u64, mut reseeder: Rsdr) -> Result {
169 | // Because generating more values than `i64::MAX` takes centuries on
170 | // current hardware, we just clamp to that value.
171 | // Also we set a threshold of 0, which indicates no limit, to that
172 | // value.
173 | let threshold = if threshold == 0 {
174 | i64::MAX
175 | } else if threshold <= i64::MAX as u64 {
176 | threshold as i64
177 | } else {
178 | i64::MAX
179 | };
180 |
181 | let inner = R::try_from_rng(&mut reseeder)?;
182 |
183 | Ok(ReseedingCore {
184 | inner,
185 | reseeder,
186 | threshold,
187 | bytes_until_reseed: threshold,
188 | })
189 | }
190 |
191 | /// Reseed the internal PRNG.
192 | fn reseed(&mut self) -> Result<(), Rsdr::Error> {
193 | R::try_from_rng(&mut self.reseeder).map(|result| {
194 | self.bytes_until_reseed = self.threshold;
195 | self.inner = result
196 | })
197 | }
198 |
199 | #[inline(never)]
200 | fn reseed_and_generate(&mut self, results: &mut ::Results) {
201 | trace!("Reseeding RNG (periodic reseed)");
202 |
203 | let num_bytes = size_of_val(results.as_ref());
204 |
205 | if let Err(e) = self.reseed() {
206 | warn!("Reseeding RNG failed: {}", e);
207 | let _ = e;
208 | }
209 |
210 | self.bytes_until_reseed = self.threshold - num_bytes as i64;
211 | self.inner.generate(results);
212 | }
213 | }
214 |
215 | impl CryptoBlockRng for ReseedingCore
216 | where
217 | R: BlockRngCore
- + SeedableRng + CryptoBlockRng,
218 | Rsdr: TryCryptoRng,
219 | {
220 | }
221 |
222 | #[cfg(feature = "std_rng")]
223 | #[cfg(test)]
224 | mod test {
225 | use crate::Rng;
226 | use crate::rngs::std::Core;
227 | use crate::test::const_rng;
228 |
229 | use super::ReseedingRng;
230 |
231 | #[test]
232 | fn test_reseeding() {
233 | let zero = const_rng(0);
234 | let thresh = 1; // reseed every time the buffer is exhausted
235 | let mut reseeding = ReseedingRng::::new(thresh, zero).unwrap();
236 |
237 | // RNG buffer size is [u32; 64]
238 | // Debug is only implemented up to length 32 so use two arrays
239 | let mut buf = ([0u32; 32], [0u32; 32]);
240 | reseeding.fill(&mut buf.0);
241 | reseeding.fill(&mut buf.1);
242 | let seq = buf;
243 | for _ in 0..10 {
244 | reseeding.fill(&mut buf.0);
245 | reseeding.fill(&mut buf.1);
246 | assert_eq!(buf, seq);
247 | }
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/src/distr/bernoulli.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | //
3 | // Licensed under the Apache License, Version 2.0 or the MIT license
5 | // , at your
6 | // option. This file may not be copied, modified, or distributed
7 | // except according to those terms.
8 |
9 | //! The Bernoulli distribution `Bernoulli(p)`.
10 |
11 | use crate::Rng;
12 | use crate::distr::Distribution;
13 | use core::fmt;
14 |
15 | #[cfg(feature = "serde")]
16 | use serde::{Deserialize, Serialize};
17 |
18 | /// The [Bernoulli distribution](https://en.wikipedia.org/wiki/Bernoulli_distribution) `Bernoulli(p)`.
19 | ///
20 | /// This distribution describes a single boolean random variable, which is true
21 | /// with probability `p` and false with probability `1 - p`.
22 | /// It is a special case of the Binomial distribution with `n = 1`.
23 | ///
24 | /// # Plot
25 | ///
26 | /// The following plot shows the Bernoulli distribution with `p = 0.1`,
27 | /// `p = 0.5`, and `p = 0.9`.
28 | ///
29 | /// 
30 | ///
31 | /// # Example
32 | ///
33 | /// ```rust
34 | /// use rand::distr::{Bernoulli, Distribution};
35 | ///
36 | /// let d = Bernoulli::new(0.3).unwrap();
37 | /// let v = d.sample(&mut rand::rng());
38 | /// println!("{} is from a Bernoulli distribution", v);
39 | /// ```
40 | ///
41 | /// # Precision
42 | ///
43 | /// This `Bernoulli` distribution uses 64 bits from the RNG (a `u64`),
44 | /// so only probabilities that are multiples of 2-64 can be
45 | /// represented.
46 | #[derive(Clone, Copy, Debug, PartialEq)]
47 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48 | pub struct Bernoulli {
49 | /// Probability of success, relative to the maximal integer.
50 | p_int: u64,
51 | }
52 |
53 | // To sample from the Bernoulli distribution we use a method that compares a
54 | // random `u64` value `v < (p * 2^64)`.
55 | //
56 | // If `p == 1.0`, the integer `v` to compare against can not represented as a
57 | // `u64`. We manually set it to `u64::MAX` instead (2^64 - 1 instead of 2^64).
58 | // Note that value of `p < 1.0` can never result in `u64::MAX`, because an
59 | // `f64` only has 53 bits of precision, and the next largest value of `p` will
60 | // result in `2^64 - 2048`.
61 | //
62 | // Also there is a 100% theoretical concern: if someone consistently wants to
63 | // generate `true` using the Bernoulli distribution (i.e. by using a probability
64 | // of `1.0`), just using `u64::MAX` is not enough. On average it would return
65 | // false once every 2^64 iterations. Some people apparently care about this
66 | // case.
67 | //
68 | // That is why we special-case `u64::MAX` to always return `true`, without using
69 | // the RNG, and pay the performance price for all uses that *are* reasonable.
70 | // Luckily, if `new()` and `sample` are close, the compiler can optimize out the
71 | // extra check.
72 | const ALWAYS_TRUE: u64 = u64::MAX;
73 |
74 | // This is just `2.0.powi(64)`, but written this way because it is not available
75 | // in `no_std` mode.
76 | const SCALE: f64 = 2.0 * (1u64 << 63) as f64;
77 |
78 | /// Error type returned from [`Bernoulli::new`].
79 | #[derive(Clone, Copy, Debug, PartialEq, Eq)]
80 | pub enum BernoulliError {
81 | /// `p < 0` or `p > 1`.
82 | InvalidProbability,
83 | }
84 |
85 | impl fmt::Display for BernoulliError {
86 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 | f.write_str(match self {
88 | BernoulliError::InvalidProbability => "p is outside [0, 1] in Bernoulli distribution",
89 | })
90 | }
91 | }
92 |
93 | #[cfg(feature = "std")]
94 | impl std::error::Error for BernoulliError {}
95 |
96 | impl Bernoulli {
97 | /// Construct a new `Bernoulli` with the given probability of success `p`.
98 | ///
99 | /// # Precision
100 | ///
101 | /// For `p = 1.0`, the resulting distribution will always generate true.
102 | /// For `p = 0.0`, the resulting distribution will always generate false.
103 | ///
104 | /// This method is accurate for any input `p` in the range `[0, 1]` which is
105 | /// a multiple of 2-64. (Note that not all multiples of
106 | /// 2-64 in `[0, 1]` can be represented as a `f64`.)
107 | #[inline]
108 | pub fn new(p: f64) -> Result {
109 | if !(0.0..1.0).contains(&p) {
110 | if p == 1.0 {
111 | return Ok(Bernoulli { p_int: ALWAYS_TRUE });
112 | }
113 | return Err(BernoulliError::InvalidProbability);
114 | }
115 | Ok(Bernoulli {
116 | p_int: (p * SCALE) as u64,
117 | })
118 | }
119 |
120 | /// Construct a new `Bernoulli` with the probability of success of
121 | /// `numerator`-in-`denominator`. I.e. `new_ratio(2, 3)` will return
122 | /// a `Bernoulli` with a 2-in-3 chance, or about 67%, of returning `true`.
123 | ///
124 | /// return `true`. If `numerator == 0` it will always return `false`.
125 | /// For `numerator > denominator` and `denominator == 0`, this returns an
126 | /// error. Otherwise, for `numerator == denominator`, samples are always
127 | /// true; for `numerator == 0` samples are always false.
128 | #[inline]
129 | pub fn from_ratio(numerator: u32, denominator: u32) -> Result {
130 | if numerator > denominator || denominator == 0 {
131 | return Err(BernoulliError::InvalidProbability);
132 | }
133 | if numerator == denominator {
134 | return Ok(Bernoulli { p_int: ALWAYS_TRUE });
135 | }
136 | let p_int = ((f64::from(numerator) / f64::from(denominator)) * SCALE) as u64;
137 | Ok(Bernoulli { p_int })
138 | }
139 |
140 | #[inline]
141 | /// Returns the probability (`p`) of the distribution.
142 | ///
143 | /// This value may differ slightly from the input due to loss of precision.
144 | pub fn p(&self) -> f64 {
145 | if self.p_int == ALWAYS_TRUE {
146 | 1.0
147 | } else {
148 | (self.p_int as f64) / SCALE
149 | }
150 | }
151 | }
152 |
153 | impl Distribution for Bernoulli {
154 | #[inline]
155 | fn sample(&self, rng: &mut R) -> bool {
156 | // Make sure to always return true for p = 1.0.
157 | if self.p_int == ALWAYS_TRUE {
158 | return true;
159 | }
160 | let v: u64 = rng.random();
161 | v < self.p_int
162 | }
163 | }
164 |
165 | #[cfg(test)]
166 | mod test {
167 | use super::Bernoulli;
168 | use crate::Rng;
169 | use crate::distr::Distribution;
170 |
171 | #[test]
172 | #[cfg(feature = "serde")]
173 | fn test_serializing_deserializing_bernoulli() {
174 | let coin_flip = Bernoulli::new(0.5).unwrap();
175 | let de_coin_flip: Bernoulli =
176 | postcard::from_bytes(&postcard::to_allocvec(&coin_flip).unwrap()).unwrap();
177 |
178 | assert_eq!(coin_flip.p_int, de_coin_flip.p_int);
179 | }
180 |
181 | #[test]
182 | fn test_trivial() {
183 | // We prefer to be explicit here.
184 | #![allow(clippy::bool_assert_comparison)]
185 |
186 | let mut r = crate::test::rng(1);
187 | let always_false = Bernoulli::new(0.0).unwrap();
188 | let always_true = Bernoulli::new(1.0).unwrap();
189 | for _ in 0..5 {
190 | assert_eq!(r.sample::(&always_false), false);
191 | assert_eq!(r.sample::(&always_true), true);
192 | assert_eq!(Distribution::::sample(&always_false, &mut r), false);
193 | assert_eq!(Distribution::::sample(&always_true, &mut r), true);
194 | }
195 | }
196 |
197 | #[test]
198 | #[cfg_attr(miri, ignore)] // Miri is too slow
199 | fn test_average() {
200 | const P: f64 = 0.3;
201 | const NUM: u32 = 3;
202 | const DENOM: u32 = 10;
203 | let d1 = Bernoulli::new(P).unwrap();
204 | let d2 = Bernoulli::from_ratio(NUM, DENOM).unwrap();
205 | const N: u32 = 100_000;
206 |
207 | let mut sum1: u32 = 0;
208 | let mut sum2: u32 = 0;
209 | let mut rng = crate::test::rng(2);
210 | for _ in 0..N {
211 | if d1.sample(&mut rng) {
212 | sum1 += 1;
213 | }
214 | if d2.sample(&mut rng) {
215 | sum2 += 1;
216 | }
217 | }
218 | let avg1 = (sum1 as f64) / (N as f64);
219 | assert!((avg1 - P).abs() < 5e-3);
220 |
221 | let avg2 = (sum2 as f64) / (N as f64);
222 | assert!((avg2 - (NUM as f64) / (DENOM as f64)).abs() < 5e-3);
223 | }
224 |
225 | #[test]
226 | fn value_stability() {
227 | let mut rng = crate::test::rng(3);
228 | let distr = Bernoulli::new(0.4532).unwrap();
229 | let mut buf = [false; 10];
230 | for x in &mut buf {
231 | *x = rng.sample(distr);
232 | }
233 | assert_eq!(
234 | buf,
235 | [
236 | true, false, false, true, false, false, true, true, true, true
237 | ]
238 | );
239 | }
240 |
241 | #[test]
242 | fn bernoulli_distributions_can_be_compared() {
243 | assert_eq!(Bernoulli::new(1.0), Bernoulli::new(1.0));
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/src/distr/distribution.rs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Developers of the Rand project.
2 | // Copyright 2013-2017 The Rust Project Developers.
3 | //
4 | // Licensed under the Apache License, Version 2.0 or the MIT license
6 | // , at your
7 | // option. This file may not be copied, modified, or distributed
8 | // except according to those terms.
9 |
10 | //! Distribution trait and associates
11 |
12 | use crate::Rng;
13 | #[cfg(feature = "alloc")]
14 | use alloc::string::String;
15 | use core::iter;
16 |
17 | /// Types (distributions) that can be used to create a random instance of `T`.
18 | ///
19 | /// It is possible to sample from a distribution through both the
20 | /// `Distribution` and [`Rng`] traits, via `distr.sample(&mut rng)` and
21 | /// `rng.sample(distr)`. They also both offer the [`sample_iter`] method, which
22 | /// produces an iterator that samples from the distribution.
23 | ///
24 | /// All implementations are expected to be immutable; this has the significant
25 | /// advantage of not needing to consider thread safety, and for most
26 | /// distributions efficient state-less sampling algorithms are available.
27 | ///
28 | /// Implementations are typically expected to be portable with reproducible
29 | /// results when used with a PRNG with fixed seed; see the
30 | /// [portability chapter](https://rust-random.github.io/book/portability.html)
31 | /// of The Rust Rand Book. In some cases this does not apply, e.g. the `usize`
32 | /// type requires different sampling on 32-bit and 64-bit machines.
33 | ///
34 | /// [`sample_iter`]: Distribution::sample_iter
35 | pub trait Distribution {
36 | /// Generate a random value of `T`, using `rng` as the source of randomness.
37 | fn sample(&self, rng: &mut R) -> T;
38 |
39 | /// Create an iterator that generates random values of `T`, using `rng` as
40 | /// the source of randomness.
41 | ///
42 | /// Note that this function takes `self` by value. This works since
43 | /// `Distribution` is impl'd for `&D` where `D: Distribution`,
44 | /// however borrowing is not automatic hence `distr.sample_iter(...)` may
45 | /// need to be replaced with `(&distr).sample_iter(...)` to borrow or
46 | /// `(&*distr).sample_iter(...)` to reborrow an existing reference.
47 | ///
48 | /// # Example
49 | ///
50 | /// ```
51 | /// use rand::distr::{Distribution, Alphanumeric, Uniform, StandardUniform};
52 | ///
53 | /// let mut rng = rand::rng();
54 | ///
55 | /// // Vec of 16 x f32:
56 | /// let v: Vec = StandardUniform.sample_iter(&mut rng).take(16).collect();
57 | ///
58 | /// // String:
59 | /// let s: String = Alphanumeric
60 | /// .sample_iter(&mut rng)
61 | /// .take(7)
62 | /// .map(char::from)
63 | /// .collect();
64 | ///
65 | /// // Dice-rolling:
66 | /// let die_range = Uniform::new_inclusive(1, 6).unwrap();
67 | /// let mut roll_die = die_range.sample_iter(&mut rng);
68 | /// while roll_die.next().unwrap() != 6 {
69 | /// println!("Not a 6; rolling again!");
70 | /// }
71 | /// ```
72 | fn sample_iter(self, rng: R) -> Iter
73 | where
74 | R: Rng,
75 | Self: Sized,
76 | {
77 | Iter {
78 | distr: self,
79 | rng,
80 | phantom: core::marker::PhantomData,
81 | }
82 | }
83 |
84 | /// Map sampled values to type `S`
85 | ///
86 | /// # Example
87 | ///
88 | /// ```
89 | /// use rand::distr::{Distribution, Uniform};
90 | ///
91 | /// let die = Uniform::new_inclusive(1, 6).unwrap();
92 | /// let even_number = die.map(|num| num % 2 == 0);
93 | /// while !even_number.sample(&mut rand::rng()) {
94 | /// println!("Still odd; rolling again!");
95 | /// }
96 | /// ```
97 | fn map(self, func: F) -> Map
98 | where
99 | F: Fn(T) -> S,
100 | Self: Sized,
101 | {
102 | Map {
103 | distr: self,
104 | func,
105 | phantom: core::marker::PhantomData,
106 | }
107 | }
108 | }
109 |
110 | impl + ?Sized> Distribution for &D {
111 | fn sample(&self, rng: &mut R) -> T {
112 | (*self).sample(rng)
113 | }
114 | }
115 |
116 | /// An iterator over a [`Distribution`]
117 | ///
118 | /// This iterator yields random values of type `T` with distribution `D`
119 | /// from a random generator of type `R`.
120 | ///
121 | /// Construct this `struct` using [`Distribution::sample_iter`] or
122 | /// [`Rng::sample_iter`]. It is also used by [`Rng::random_iter`] and
123 | /// [`crate::random_iter`].
124 | #[derive(Debug)]
125 | pub struct Iter {
126 | distr: D,
127 | rng: R,
128 | phantom: core::marker::PhantomData,
129 | }
130 |
131 | impl Iterator for Iter
132 | where
133 | D: Distribution,
134 | R: Rng,
135 | {
136 | type Item = T;
137 |
138 | #[inline(always)]
139 | fn next(&mut self) -> Option {
140 | // Here, self.rng may be a reference, but we must take &mut anyway.
141 | // Even if sample could take an R: Rng by value, we would need to do this
142 | // since Rng is not copyable and we cannot enforce that this is "reborrowable".
143 | Some(self.distr.sample(&mut self.rng))
144 | }
145 |
146 | fn size_hint(&self) -> (usize, Option) {
147 | (usize::MAX, None)
148 | }
149 | }
150 |
151 | impl iter::FusedIterator for Iter
152 | where
153 | D: Distribution,
154 | R: Rng,
155 | {
156 | }
157 |
158 | /// A [`Distribution`] which maps sampled values to type `S`
159 | ///
160 | /// This `struct` is created by the [`Distribution::map`] method.
161 | /// See its documentation for more.
162 | #[derive(Debug)]
163 | pub struct Map