Upgrade rust/crates/rand to 0.8.0 am: 8f9af988c5 am: 838c6d95c7
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/rand/+/1534331
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: I4b9ab893e1f8ca938ee98d2e75ea6ea4f78a71b2
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 93fa283..37219d9 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
{
"git": {
- "sha1": "074cb6a997f91db653f8a53c755ddc07495ab429"
+ "sha1": "98a1aaf28e7bc272c12796d96401c177bf2205e4"
}
}
diff --git a/.github/ISSUE_TEMPLATE/compile-issue.md b/.github/ISSUE_TEMPLATE/compile-issue.md
deleted file mode 100644
index 8a8354b..0000000
--- a/.github/ISSUE_TEMPLATE/compile-issue.md
+++ /dev/null
@@ -1,16 +0,0 @@
----
-name: Compile issue
-about: Report / ask about a compilation issue
-title: ''
-labels: ''
-assignees: ''
-
----
-
-# Common issues
-
-**Problem**: `rand_hc::Hc128Rng: rand_core::SeedableRng` (or other RNG)
-
-**Quick solution**: `cargo update`
-
-**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.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 90c57c8..0000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,18 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: ''
-assignees: ''
-
----
-
-## Background
-
-**What is your motivation?**
-
-**What type of application is this?** (E.g. cryptography, game, numerical simulation)
-
-## Feature request
-
-<details here>
diff --git a/.github/ISSUE_TEMPLATE/other.md b/.github/ISSUE_TEMPLATE/other.md
deleted file mode 100644
index a3e76ca..0000000
--- a/.github/ISSUE_TEMPLATE/other.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-name: Other
-about: empty template
-title: ''
-labels: ''
-assignees: ''
-
----
-
-
diff --git a/Android.bp b/Android.bp
index 5b2b7e0..f489cd6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -10,12 +10,13 @@
"alloc",
"default",
"getrandom",
- "getrandom_package",
"libc",
+ "rand_chacha",
+ "rand_hc",
"std",
+ "std_rng",
],
rustlibs: [
- "libgetrandom",
"liblibc",
"librand_chacha",
"librand_core",
@@ -24,8 +25,8 @@
// dependent_library ["feature_list"]
// cfg-if-0.1.10
-// getrandom-0.1.15 "std"
-// libc-0.2.77
-// ppv-lite86-0.2.9 "simd,std"
-// rand_chacha-0.2.2 "std"
-// rand_core-0.5.1 "alloc,getrandom,std"
+// getrandom-0.2.0 "std"
+// libc-0.2.81
+// ppv-lite86-0.2.10 "simd,std"
+// rand_chacha-0.3.0 "std"
+// rand_core-0.6.0 "alloc,getrandom,std"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b519d48..c4815bb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,62 @@
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
+## [0.8.0] - 2020-12-18
+### Platform support
+- The minimum supported Rust version is now 1.36 (#1011)
+- `getrandom` updated to v0.2 (#1041)
+- Remove `wasm-bindgen` and `stdweb` feature flags. For details of WASM support,
+ see the [getrandom documentation](https://docs.rs/getrandom/latest). (#948)
+- `ReadRng::next_u32` and `next_u64` now use little-Endian conversion instead
+ of native-Endian, affecting results on Big-Endian platforms (#1061)
+- The `nightly` feature no longer implies the `simd_support` feature (#1048)
+- Fix `simd_support` feature to work on current nightlies (#1056)
+
+### Rngs
+- `ThreadRng` is no longer `Copy` to enable safe usage within thread-local destructors (#1035)
+- `gen_range(a, b)` was replaced with `gen_range(a..b)`. `gen_range(a..=b)` is
+ also supported. Note that `a` and `b` can no longer be references or SIMD types. (#744, #1003)
+- Replace `AsByteSliceMut` with `Fill` and add support for `[bool], [char], [f32], [f64]` (#940)
+- Restrict `rand::rngs::adapter` to `std` (#1027; see also #928)
+- `StdRng`: add new `std_rng` feature flag (enabled by default, but might need
+ to be used if disabling default crate features) (#948)
+- `StdRng`: Switch from ChaCha20 to ChaCha12 for better performance (#1028)
+- `SmallRng`: Replace PCG algorithm with xoshiro{128,256}++ (#1038)
+
+### Sequences
+- Add `IteratorRandom::choose_stable` as an alternative to `choose` which does
+ not depend on size hints (#1057)
+- Improve accuracy and performance of `IteratorRandom::choose` (#1059)
+- Implement `IntoIterator` for `IndexVec`, replacing the `into_iter` method (#1007)
+- Add value stability tests for `seq` module (#933)
+
+### Misc
+- Support `PartialEq` and `Eq` for `StdRng`, `SmallRng` and `StepRng` (#979)
+- Added a `serde1` feature and added Serialize/Deserialize to `UniformInt` and `WeightedIndex` (#974)
+- Drop some unsafe code (#962, #963, #1011)
+- Reduce packaged crate size (#983)
+- Migrate to GitHub Actions from Travis+AppVeyor (#1073)
+
+### Distributions
+- `Alphanumeric` samples bytes instead of chars (#935)
+- `Uniform` now supports `char`, enabling `rng.gen_range('A'..='Z')` (#1068)
+- Add `UniformSampler::sample_single_inclusive` (#1003)
+
+#### Weighted sampling
+- Implement weighted sampling without replacement (#976, #1013)
+- `rand::distributions::alias_method::WeightedIndex` was moved to `rand_distr::WeightedAliasIndex`.
+ The simpler alternative `rand::distribution::WeightedIndex` remains. (#945)
+- Improve treatment of rounding errors in `WeightedIndex::update_weights` (#956)
+- `WeightedIndex`: return error on NaN instead of panic (#1005)
+
+### Documentation
+- Document types supported by `random` (#994)
+- Document notes on password generation (#995)
+- Note that `SmallRng` may not be the best choice for performance and in some
+ other cases (#1038)
+- Use `doc(cfg)` to annotate feature-gated items (#1019)
+- Adjust README (#1065)
+
## [0.7.3] - 2020-01-10
### Fixes
- The `Bernoulli` distribution constructors now reports an error on NaN and on
@@ -40,7 +96,7 @@
- Fix or squelch issues from Clippy lints (#840)
### Additions
-- Add a `no_std` target to CI to continously evaluate `no_std` status (#844)
+- Add a `no_std` target to CI to continuously evaluate `no_std` status (#844)
- `WeightedIndex`: allow adjusting a sub-set of weights (#866)
## [0.7.0] - 2019-06-28
@@ -400,7 +456,7 @@
## [0.3.14] - 2016-02-13
### Fixed
-- Inline definitions from winapi/advapi32, wich decreases build times
+- Inline definitions from winapi/advapi32, which decreases build times
## [0.3.13] - 2016-01-09
diff --git a/Cargo.lock b/Cargo.lock
index a03987b..be7d3a4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,388 +1,184 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
-name = "base-x"
-version = "0.2.5"
+name = "bincode"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "bumpalo"
-version = "2.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "c2-chacha"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
dependencies = [
- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder",
+ "serde",
]
[[package]]
+name = "byteorder"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+
+[[package]]
name = "cfg-if"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "discard"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "getrandom"
-version = "0.1.12"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if",
+ "libc",
+ "wasi",
]
[[package]]
-name = "itoa"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "libc"
-version = "0.2.62"
+version = "0.2.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"
+
+[[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
[[package]]
name = "log"
-version = "0.4.8"
+version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if",
]
[[package]]
-name = "packed_simd"
-version = "0.3.3"
+name = "packed_simd_2"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3278e0492f961fd4ae70909f56b2723a7e8d01a228427294e19cdfdebda89a17"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if",
+ "libm",
]
[[package]]
name = "ppv-lite86"
-version = "0.2.5"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro2"
-version = "0.4.30"
+version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
dependencies = [
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid",
]
[[package]]
name = "quote"
-version = "0.6.13"
+version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2",
]
[[package]]
name = "rand"
-version = "0.7.3"
+version = "0.8.0"
dependencies = [
- "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bincode",
+ "libc",
+ "log",
+ "packed_simd_2",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+ "rand_pcg",
+ "serde",
]
[[package]]
name = "rand_chacha"
-version = "0.2.1"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
dependencies = [
- "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ppv-lite86",
+ "rand_core",
]
[[package]]
name = "rand_core"
-version = "0.5.1"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8b34ba8cfb21243bd8df91854c830ff0d785fff2e82ebd4434c2644cb9ada18"
dependencies = [
- "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getrandom",
]
[[package]]
name = "rand_hc"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
dependencies = [
- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core",
]
[[package]]
name = "rand_pcg"
-version = "0.2.1"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7de198537002b913568a3847e53535ace266f93526caf5c360ec41d72c5787f0"
dependencies = [
- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core",
]
[[package]]
-name = "rustc_version"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
name = "serde"
-version = "1.0.100"
+version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"
+dependencies = [
+ "serde_derive",
+]
[[package]]
name = "serde_derive"
-version = "1.0.100"
+version = "1.0.115"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"
dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "sha1"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "stdweb"
-version = "0.4.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "stdweb-internal-macros 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "stdweb-internal-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "stdweb-derive"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "stdweb-internal-macros"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "base-x 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "stdweb-internal-runtime"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "syn"
-version = "0.15.44"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2",
+ "quote",
+ "syn",
]
[[package]]
name = "syn"
-version = "1.0.5"
+version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
]
[[package]]
name = "unicode-xid"
-version = "0.1.0"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "wasi"
-version = "0.7.0"
+version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
- "wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[metadata]
-"checksum base-x 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76f4eae81729e69bb1819a26c6caac956cc429238388091f98cb6cd858f16443"
-"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
-"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
-"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
-"checksum discard 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
-"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
-"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
-"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
-"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
-"checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
-"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
-"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
-"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
-"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
-"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
-"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
-"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
-"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
-"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
-"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
-"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
-"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a"
-"checksum serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "11e410fde43e157d789fc290d26bc940778ad0fdd47836426fbac36573710dbb"
-"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
-"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
-"checksum stdweb 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a68c0ce28cf7400ed022e18da3c4591e14e1df02c70e93573cc59921b3923aeb"
-"checksum stdweb-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930"
-"checksum stdweb-internal-macros 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e68f7d08b76979a43e93fe043b66d2626e35d41d68b0b85519202c6dd8ac59fa"
-"checksum stdweb-internal-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d52317523542cc0af5b7e31017ad0f7d1e78da50455e38d5657cd17754f617da"
-"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
-"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
-"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
-"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
-"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
-"checksum wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "dcddca308b16cd93c2b67b126c688e5467e4ef2e28200dc7dfe4ae284f2faefc"
-"checksum wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "f805d9328b5fc7e5c6399960fd1889271b9b58ae17bdb2417472156cc9fafdd0"
-"checksum wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff88201a482abfc63921621f6cb18eb1efd74f136b05e5841e7f8ca434539e9"
-"checksum wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "6a433d89ecdb9f77d46fcf00c8cf9f3467b7de9954d8710c175f61e2e245bb0e"
-"checksum wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "d41fc1bc3570cdf8d108c15e014045fd45a95bb5eb36605f96a90461fc34027d"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
diff --git a/Cargo.toml b/Cargo.toml
index 78a29b0..e44e775 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,13 +13,13 @@
[package]
edition = "2018"
name = "rand"
-version = "0.7.3"
+version = "0.8.0"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
-exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
+include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"]
autobenches = true
description = "Random number generators and other randomness functionality.\n"
-homepage = "https://crates.io/crates/rand"
-documentation = "https://rust-random.github.io/rand/"
+homepage = "https://rust-random.github.io/book"
+documentation = "https://docs.rs/rand"
readme = "README.md"
keywords = ["random", "rng"]
categories = ["algorithms", "no-std"]
@@ -27,54 +27,51 @@
repository = "https://github.com/rust-random/rand"
[package.metadata.docs.rs]
all-features = true
-[dependencies.getrandom_package]
-version = "0.1.1"
-optional = true
-package = "getrandom"
-
+rustdoc-args = ["--cfg", "doc_cfg"]
[dependencies.log]
version = "0.4.4"
optional = true
[dependencies.packed_simd]
-version = "0.3"
+version = "0.3.4"
features = ["into_bits"]
optional = true
+package = "packed_simd_2"
[dependencies.rand_core]
-version = "0.5.1"
+version = "0.6.0"
-[dependencies.rand_pcg]
-version = "0.2"
+[dependencies.serde]
+version = "1.0.103"
+features = ["derive"]
optional = true
+[dev-dependencies.bincode]
+version = "1.2.1"
+
[dev-dependencies.rand_hc]
-version = "0.2"
+version = "0.3.0"
[dev-dependencies.rand_pcg]
-version = "0.2"
+version = "0.3.0"
[features]
alloc = ["rand_core/alloc"]
-default = ["std"]
-getrandom = ["getrandom_package", "rand_core/getrandom"]
-nightly = ["simd_support"]
-serde1 = []
+default = ["std", "std_rng"]
+getrandom = ["rand_core/getrandom"]
+nightly = []
+serde1 = ["serde"]
simd_support = ["packed_simd"]
-small_rng = ["rand_pcg"]
+small_rng = []
std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
-stdweb = ["getrandom_package/stdweb"]
-wasm-bindgen = ["getrandom_package/wasm-bindgen"]
+std_rng = ["rand_chacha", "rand_hc"]
[target."cfg(not(target_os = \"emscripten\"))".dependencies.rand_chacha]
-version = "0.2.1"
+version = "0.3.0"
+optional = true
default-features = false
[target."cfg(target_os = \"emscripten\")".dependencies.rand_hc]
-version = "0.2"
+version = "0.3.0"
+optional = true
[target."cfg(unix)".dependencies.libc]
version = "0.2.22"
optional = true
default-features = false
-[badges.appveyor]
-repository = "rust-random/rand"
-
-[badges.travis-ci]
-repository = "rust-random/rand"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index ac64187..aee917c 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,44 +1,45 @@
[package]
name = "rand"
-version = "0.7.3"
+version = "0.8.0"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
license = "MIT OR Apache-2.0"
readme = "README.md"
repository = "https://github.com/rust-random/rand"
-documentation = "https://rust-random.github.io/rand/"
-homepage = "https://crates.io/crates/rand"
+documentation = "https://docs.rs/rand"
+homepage = "https://rust-random.github.io/book"
description = """
Random number generators and other randomness functionality.
"""
keywords = ["random", "rng"]
categories = ["algorithms", "no-std"]
-exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
autobenches = true
edition = "2018"
-
-[badges]
-travis-ci = { repository = "rust-random/rand" }
-appveyor = { repository = "rust-random/rand" }
+include = ["src/", "LICENSE-*", "README.md", "CHANGELOG.md", "COPYRIGHT"]
[features]
# Meta-features:
-default = ["std"] # without "std" rand uses libcore
-nightly = ["simd_support"] # enables all features requiring nightly rust
-serde1 = [] # does nothing, deprecated
+default = ["std", "std_rng"]
+nightly = [] # enables performance optimizations requiring nightly rust
+serde1 = ["serde"]
-# Optional dependencies:
+# Option (enabled by default): without "std" rand uses libcore; this option
+# enables functionality expected to be available on a standard platform.
std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
-alloc = ["rand_core/alloc"] # enables Vec and Box support (without std)
-# re-export optional WASM dependencies to avoid breakage:
-# Warning: wasm-bindgen and stdweb features will be removed in rand 0.8;
-# recommended to activate via the getrandom crate instead.
-wasm-bindgen = ["getrandom_package/wasm-bindgen"]
-stdweb = ["getrandom_package/stdweb"]
-getrandom = ["getrandom_package", "rand_core/getrandom"]
-# Configuration:
-simd_support = ["packed_simd"] # enables SIMD support
-small_rng = ["rand_pcg"] # enables SmallRng
+# Option: "alloc" enables support for Vec and Box when not using "std"
+alloc = ["rand_core/alloc"]
+
+# Option: use getrandom package for seeding
+getrandom = ["rand_core/getrandom"]
+
+# Option (requires nightly): experimental SIMD support
+simd_support = ["packed_simd"]
+
+# Option (enabled by default): enable StdRng
+std_rng = ["rand_chacha", "rand_hc"]
+
+# Option: enable SmallRng
+small_rng = []
[workspace]
members = [
@@ -47,22 +48,17 @@
"rand_chacha",
"rand_hc",
"rand_pcg",
- "tests/wasm_bindgen",
]
[dependencies]
-rand_core = { path = "rand_core", version = "0.5.1" }
-rand_pcg = { path = "rand_pcg", version = "0.2", optional = true }
-# Do not depend on 'getrandom_package' directly; use the 'getrandom' feature!
-# This is a dependency because: we forward wasm feature flags
-# This is renamed because: we need getrandom to depend on rand_core/getrandom
-getrandom_package = { version = "0.1.1", package = "getrandom", optional = true }
+rand_core = { path = "rand_core", version = "0.6.0" }
log = { version = "0.4.4", optional = true }
+serde = { version = "1.0.103", features = ["derive"], optional = true }
[dependencies.packed_simd]
# NOTE: so far no version works reliably due to dependence on unstable features
-version = "0.3"
-# git = "https://github.com/rust-lang-nursery/packed_simd"
+package = "packed_simd_2"
+version = "0.3.4"
optional = true
features = ["into_bits"]
@@ -73,14 +69,19 @@
# Emscripten does not support 128-bit integers, which are used by ChaCha code.
# We work around this by using a different RNG.
[target.'cfg(not(target_os = "emscripten"))'.dependencies]
-rand_chacha = { path = "rand_chacha", version = "0.2.1", default-features = false }
+rand_chacha = { path = "rand_chacha", version = "0.3.0", default-features = false, optional = true }
[target.'cfg(target_os = "emscripten")'.dependencies]
-rand_hc = { path = "rand_hc", version = "0.2" }
+rand_hc = { path = "rand_hc", version = "0.3.0", optional = true }
[dev-dependencies]
-rand_pcg = { path = "rand_pcg", version = "0.2" }
+rand_pcg = { path = "rand_pcg", version = "0.3.0" }
# Only for benches:
-rand_hc = { path = "rand_hc", version = "0.2" }
+rand_hc = { path = "rand_hc", version = "0.3.0" }
+# Only to test serde1
+bincode = "1.2.1"
[package.metadata.docs.rs]
+# To build locally:
+# RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --no-deps --open
all-features = true
+rustdoc-args = ["--cfg", "doc_cfg"]
diff --git a/METADATA b/METADATA
index 39d161d..af9a0a8 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/rand/rand-0.7.3.crate"
+ value: "https://static.crates.io/crates/rand/rand-0.8.0.crate"
}
- version: "0.7.3"
+ version: "0.8.0"
license_type: NOTICE
last_upgrade_date {
year: 2020
- month: 6
- day: 18
+ month: 12
+ day: 22
}
}
diff --git a/README.md b/README.md
index c4bd676..aaf6df1 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,47 @@
# Rand
-[![Build Status](https://travis-ci.org/rust-random/rand.svg?branch=master)](https://travis-ci.org/rust-random/rand)
-[![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-random/rand?svg=true)](https://ci.appveyor.com/project/rust-random/rand)
+[![Test Status](https://github.com/rust-random/rand/workflows/Tests/badge.svg?event=push)](https://github.com/rust-random/rand/actions)
[![Crate](https://img.shields.io/crates/v/rand.svg)](https://crates.io/crates/rand)
[![Book](https://img.shields.io/badge/book-master-yellow.svg)](https://rust-random.github.io/book/)
-[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand)
+[![API](https://img.shields.io/badge/api-master-yellow.svg)](https://rust-random.github.io/rand/rand)
[![API](https://docs.rs/rand/badge.svg)](https://docs.rs/rand)
-[![Minimum rustc version](https://img.shields.io/badge/rustc-1.32+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
+[![Minimum rustc version](https://img.shields.io/badge/rustc-1.36+-lightgray.svg)](https://github.com/rust-random/rand#rust-version-requirements)
-A Rust library for random number generation.
+A Rust library for random number generation, featuring:
-Rand provides utilities to generate random numbers, to convert them to useful
-types and distributions, and some randomness-related algorithms.
+- Easy random value generation and usage via the [`Rng`](https://docs.rs/rand/*/rand/trait.Rng.html),
+ [`SliceRandom`](https://docs.rs/rand/*/rand/seq/trait.SliceRandom.html) and
+ [`IteratorRandom`](https://docs.rs/rand/*/rand/seq/trait.IteratorRandom.html) traits
+- Secure seeding via the [`getrandom` crate](https://crates.io/crates/getrandom)
+ and fast, convenient generation via [`thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html)
+- A modular design built over [`rand_core`](https://crates.io/crates/rand_core)
+ ([see the book](https://rust-random.github.io/book/crates.html))
+- Fast implementations of the best-in-class [cryptographic](https://rust-random.github.io/book/guide-rngs.html#cryptographically-secure-pseudo-random-number-generators-csprngs) and
+ [non-cryptographic](https://rust-random.github.io/book/guide-rngs.html#basic-pseudo-random-number-generators-prngs) generators
+- A flexible [`distributions`](https://docs.rs/rand/*/rand/distributions/index.html) module
+- Samplers for a large number of random number distributions via our own
+ [`rand_distr`](https://docs.rs/rand_distr) and via
+ the [`statrs`](https://docs.rs/statrs/0.13.0/statrs/)
+- [Portably reproducible output](https://rust-random.github.io/book/portability.html)
+- `#[no_std]` compatibility (partial)
+- *Many* performance optimisations
-The core random number generation traits of Rand live in the [rand_core](
-https://crates.io/crates/rand_core) crate but are also exposed here; RNG
-implementations should prefer to use `rand_core` while most other users should
-depend on `rand`.
+It's also worth pointing out what `rand` *is not*:
+
+- Small. Most low-level crates are small, but the higher-level `rand` and
+ `rand_distr` each contain a lot of functionality.
+- Simple (implementation). We have a strong focus on correctness, speed and flexibility, but
+ not simplicity. If you prefer a small-and-simple library, there are
+ alternatives including [fastrand](https://crates.io/crates/fastrand)
+ and [oorandom](https://crates.io/crates/oorandom).
+- Slow. We take performance seriously, with considerations also for set-up
+ time of new distributions, commonly-used parameters, and parameters of the
+ current sampler.
Documentation:
+
- [The Rust Rand Book](https://rust-random.github.io/book)
-- [API reference (master)](https://rust-random.github.io/rand)
+- [API reference (master branch)](https://rust-random.github.io/rand)
- [API reference (docs.rs)](https://docs.rs/rand)
@@ -30,7 +51,7 @@
```toml
[dependencies]
-rand = "0.7"
+rand = "0.8.0"
```
To get started using Rand, see [The Book](https://rust-random.github.io/book).
@@ -38,6 +59,27 @@
## Versions
+Rand is *mature* (suitable for general usage, with infrequent breaking releases
+which minimise breakage) but not yet at 1.0. We maintain compatibility with
+pinned versions of the Rust compiler (see below).
+
+Current Rand versions are:
+
+- Version 0.7 was released in June 2019, moving most non-uniform distributions
+ to an external crate, moving `from_entropy` to `SeedableRng`, and many small
+ changes and fixes.
+- Version 0.8 was released in December 2020 with many small changes.
+
+A detailed [changelog](CHANGELOG.md) is available for releases.
+
+When upgrading to the next minor series (especially 0.4 → 0.5), we recommend
+reading the [Upgrade Guide](https://rust-random.github.io/book/update.html).
+
+Rand has not yet reached 1.0 implying some breaking changes may arrive in the
+future ([SemVer](https://semver.org/) allows each 0.x.0 release to include
+breaking changes), but is considered *mature*: breaking changes are minimised
+and breaking releases are infrequent.
+
Rand libs have inter-dependencies and make use of the
[semver trick](https://github.com/dtolnay/semver-trick/) in order to make traits
compatible across crate versions. (This is especially important for `RngCore`
@@ -47,26 +89,6 @@
`rand_core_0_3_0::SeedableRng` are distinct, incompatible traits, which can
cause build errors. Usually, running `cargo update` is enough to fix any issues.
-The Rand lib is not yet stable, however we are careful to limit breaking changes
-and warn via deprecation wherever possible. Patch versions never introduce
-breaking changes. The following minor versions are supported:
-
-- Version 0.7 was released in June 2019, moving most non-uniform distributions
- to an external crate, moving `from_entropy` to `SeedableRng`, and many small
- changes and fixes.
-- Version 0.6 was released in November 2018, redesigning the `seq` module,
- moving most PRNGs to external crates, and many small changes.
-- Version 0.5 was released in May 2018, as a major reorganisation
- (introducing `RngCore` and `rand_core`, and deprecating `Rand` and the
- previous distribution traits).
-- Version 0.4 was released in December 2017, but contained almost no breaking
- changes from the 0.3 series.
-
-A detailed [changelog](CHANGELOG.md) is available.
-
-When upgrading to the next minor series (especially 0.4 → 0.5), we recommend
-reading the [Upgrade Guide](https://rust-random.github.io/book/update.html).
-
### Yanked versions
Some versions of Rand crates have been yanked ("unreleased"). Where this occurs,
@@ -75,14 +97,14 @@
### Rust version requirements
-Since version 0.7, Rand requires **Rustc version 1.32 or greater**.
-Rand 0.5 requires Rustc 1.22 or greater while versions
-0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or
-greater. Subsets of the Rand code may work with older Rust versions, but this
-is not supported.
+Since version 0.8, Rand requires **Rustc version 1.36 or greater**.
+Rand 0.7 requires Rustc 1.32 or greater while versions 0.5 require Rustc 1.22 or
+greater, and 0.4 and 0.3 (since approx. June 2017) require Rustc version 1.15 or
+greater. Subsets of the Rand code may work with older Rust versions, but this is
+not supported.
-Travis CI always has a build with a pinned version of Rustc matching the oldest
-supported Rust release. The current policy is that this can be updated in any
+Continuous Integration (CI) will always test the minimum supported Rustc version
+(the MSRV). The current policy is that this can be updated in any
Rand release if required, but the change must be noted in the changelog.
## Crate Features
@@ -90,26 +112,26 @@
Rand is built with these features enabled by default:
- `std` enables functionality dependent on the `std` lib
-- `alloc` (implied by `std`) enables functionality requiring an allocator (when using this feature in `no_std`, Rand requires Rustc version 1.36 or greater)
+- `alloc` (implied by `std`) enables functionality requiring an allocator
- `getrandom` (implied by `std`) is an optional dependency providing the code
behind `rngs::OsRng`
+- `std_rng` enables inclusion of `StdRng`, `thread_rng` and `random`
+ (the latter two *also* require that `std` be enabled)
Optionally, the following dependencies can be enabled:
-- `log` enables logging via the `log` crate
-- `stdweb` implies `getrandom/stdweb` to enable
- `getrandom` support on `wasm32-unknown-unknown`
- (will be removed in rand 0.8; activate via `getrandom` crate instead)
-- `wasm-bindgen` implies `getrandom/wasm-bindgen` to enable
- `getrandom` support on `wasm32-unknown-unknown`
- (will be removed in rand 0.8; activate via `getrandom` crate instead)
+- `log` enables logging via the `log` crate` crate
Additionally, these features configure Rand:
- `small_rng` enables inclusion of the `SmallRng` PRNG
-- `nightly` enables all experimental features
+- `nightly` enables some optimizations requiring nightly Rust
- `simd_support` (experimental) enables sampling of SIMD values
- (uniformly random SIMD integers and floats)
+ (uniformly random SIMD integers and floats), requiring nightly Rust
+
+Note that nightly features are not stable and therefore not all library and
+compiler versions will be compatible. This is especially true of Rand's
+experimental `simd_support` feature.
Rand supports limited functionality in `no_std` mode (enabled via
`default-features = false`). In this case, `OsRng` and `from_entropy` are
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index daedb78..0000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Security Policy
-
-## No guarantees
-
-Support is provided on a best-effort bases only.
-No binding guarantees can be provided.
-
-## Security premises
-
-Rand provides the trait `rand_core::CryptoRng` aka `rand::CryptoRng` as a marker
-trait. Generators implementating `RngCore` *and* `CryptoRng`, and given the
-additional constraints that:
-
-- Instances of seedable RNGs (those implementing `SeedableRng`) are
- constructed with cryptographically secure seed values
-- The state (memory) of the RNG and its seed value are not be exposed
-
-are expected to provide the following:
-
-- An attacker can gain no advantage over chance (50% for each bit) in
- predicting the RNG output, even with full knowledge of all prior outputs.
-
-For some RNGs, notably `OsRng`, `ThreadRng` and those wrapped by `ReseedingRng`,
-we provide limited mitigations against side-channel attacks:
-
-- After a process fork on Unix, there is an upper-bound on the number of bits
- output by the RNG before the processes diverge, after which outputs from
- each process's RNG are uncorrelated
-- After the state (memory) of an RNG is leaked, there is an upper-bound on the
- number of bits of output by the RNG before prediction of output by an
- observer again becomes computationally-infeasible
-
-Additionally, derivations from such an RNG (including the `Rng` trait,
-implementations of the `Distribution` trait, and `seq` algorithms) should not
-introduce signficant bias other than that expected from the operation in
-question (e.g. bias from a weighted distribution).
-
-## Supported Versions
-
-We will attempt to uphold these premises in the following crate versions,
-provided that only the latest patch version is used, and with potential
-exceptions for theoretical issues without a known exploit:
-
-| Crate | Versions | Exceptions |
-| ----- | -------- | ---------- |
-| `rand` | 0.7 | |
-| `rand` | 0.5, 0.6 | Jitter |
-| `rand` | 0.4 | Jitter, ISAAC |
-| `rand_core` | 0.2 - 0.5 | |
-| `rand_chacha` | 0.1 - 0.2 | |
-| `rand_hc` | 0.1 - 0.2 | |
-
-Explanation of exceptions:
-
-- Jitter: `JitterRng` is used as an entropy source when the primary source
- fails; this source may not be secure against side-channel attacks, see #699.
-- ISAAC: the [ISAAC](https://burtleburtle.net/bob/rand/isaacafa.html) RNG used
- to implement `thread_rng` is difficult to analyse and thus cannot provide
- strong assertions of security.
-
-## Known issues
-
-In `rand` version 0.3 (0.3.18 and later), if `OsRng` fails, `thread_rng` is
-seeded from the system time in an insecure manner.
-
-## Reporting a Vulnerability
-
-To report a vulnerability, [open a new issue](https://github.com/rust-random/rand/issues/new).
-Once the issue is resolved, the vulnerability should be [reported to RustSec](https://github.com/RustSec/advisory-db/blob/master/CONTRIBUTING.md).
diff --git a/benches/generators.rs b/benches/generators.rs
deleted file mode 100644
index 3e26408..0000000
--- a/benches/generators.rs
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(test)]
-#![allow(non_snake_case)]
-
-extern crate test;
-
-const RAND_BENCH_N: u64 = 1000;
-const BYTES_LEN: usize = 1024;
-
-use std::mem::size_of;
-use test::{black_box, Bencher};
-
-use rand::prelude::*;
-use rand::rngs::adapter::ReseedingRng;
-use rand::rngs::{mock::StepRng, OsRng};
-use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng};
-use rand_hc::Hc128Rng;
-use rand_pcg::{Pcg32, Pcg64, Pcg64Mcg};
-
-macro_rules! gen_bytes {
- ($fnn:ident, $gen:expr) => {
- #[bench]
- fn $fnn(b: &mut Bencher) {
- let mut rng = $gen;
- let mut buf = [0u8; BYTES_LEN];
- b.iter(|| {
- for _ in 0..RAND_BENCH_N {
- rng.fill_bytes(&mut buf);
- black_box(buf);
- }
- });
- b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
- }
- };
-}
-
-gen_bytes!(gen_bytes_step, StepRng::new(0, 1));
-gen_bytes!(gen_bytes_pcg32, Pcg32::from_entropy());
-gen_bytes!(gen_bytes_pcg64, Pcg64::from_entropy());
-gen_bytes!(gen_bytes_pcg64mcg, Pcg64Mcg::from_entropy());
-gen_bytes!(gen_bytes_chacha8, ChaCha8Rng::from_entropy());
-gen_bytes!(gen_bytes_chacha12, ChaCha12Rng::from_entropy());
-gen_bytes!(gen_bytes_chacha20, ChaCha20Rng::from_entropy());
-gen_bytes!(gen_bytes_hc128, Hc128Rng::from_entropy());
-gen_bytes!(gen_bytes_std, StdRng::from_entropy());
-#[cfg(feature = "small_rng")]
-gen_bytes!(gen_bytes_small, SmallRng::from_entropy());
-gen_bytes!(gen_bytes_os, OsRng);
-
-macro_rules! gen_uint {
- ($fnn:ident, $ty:ty, $gen:expr) => {
- #[bench]
- fn $fnn(b: &mut Bencher) {
- let mut rng = $gen;
- b.iter(|| {
- let mut accum: $ty = 0;
- for _ in 0..RAND_BENCH_N {
- accum = accum.wrapping_add(rng.gen::<$ty>());
- }
- accum
- });
- b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
- }
- };
-}
-
-gen_uint!(gen_u32_step, u32, StepRng::new(0, 1));
-gen_uint!(gen_u32_pcg32, u32, Pcg32::from_entropy());
-gen_uint!(gen_u32_pcg64, u32, Pcg64::from_entropy());
-gen_uint!(gen_u32_pcg64mcg, u32, Pcg64Mcg::from_entropy());
-gen_uint!(gen_u32_chacha8, u32, ChaCha8Rng::from_entropy());
-gen_uint!(gen_u32_chacha12, u32, ChaCha12Rng::from_entropy());
-gen_uint!(gen_u32_chacha20, u32, ChaCha20Rng::from_entropy());
-gen_uint!(gen_u32_hc128, u32, Hc128Rng::from_entropy());
-gen_uint!(gen_u32_std, u32, StdRng::from_entropy());
-#[cfg(feature = "small_rng")]
-gen_uint!(gen_u32_small, u32, SmallRng::from_entropy());
-gen_uint!(gen_u32_os, u32, OsRng);
-
-gen_uint!(gen_u64_step, u64, StepRng::new(0, 1));
-gen_uint!(gen_u64_pcg32, u64, Pcg32::from_entropy());
-gen_uint!(gen_u64_pcg64, u64, Pcg64::from_entropy());
-gen_uint!(gen_u64_pcg64mcg, u64, Pcg64Mcg::from_entropy());
-gen_uint!(gen_u64_chacha8, u64, ChaCha8Rng::from_entropy());
-gen_uint!(gen_u64_chacha12, u64, ChaCha12Rng::from_entropy());
-gen_uint!(gen_u64_chacha20, u64, ChaCha20Rng::from_entropy());
-gen_uint!(gen_u64_hc128, u64, Hc128Rng::from_entropy());
-gen_uint!(gen_u64_std, u64, StdRng::from_entropy());
-#[cfg(feature = "small_rng")]
-gen_uint!(gen_u64_small, u64, SmallRng::from_entropy());
-gen_uint!(gen_u64_os, u64, OsRng);
-
-macro_rules! init_gen {
- ($fnn:ident, $gen:ident) => {
- #[bench]
- fn $fnn(b: &mut Bencher) {
- let mut rng = Pcg32::from_entropy();
- b.iter(|| {
- let r2 = $gen::from_rng(&mut rng).unwrap();
- r2
- });
- }
- };
-}
-
-init_gen!(init_pcg32, Pcg32);
-init_gen!(init_pcg64, Pcg64);
-init_gen!(init_pcg64mcg, Pcg64Mcg);
-init_gen!(init_hc128, Hc128Rng);
-init_gen!(init_chacha, ChaCha20Rng);
-
-const RESEEDING_BYTES_LEN: usize = 1024 * 1024;
-const RESEEDING_BENCH_N: u64 = 16;
-
-macro_rules! reseeding_bytes {
- ($fnn:ident, $thresh:expr) => {
- #[bench]
- fn $fnn(b: &mut Bencher) {
- let mut rng = ReseedingRng::new(ChaCha20Core::from_entropy(), $thresh * 1024, OsRng);
- let mut buf = [0u8; RESEEDING_BYTES_LEN];
- b.iter(|| {
- for _ in 0..RESEEDING_BENCH_N {
- rng.fill_bytes(&mut buf);
- black_box(&buf);
- }
- });
- b.bytes = RESEEDING_BYTES_LEN as u64 * RESEEDING_BENCH_N;
- }
- };
-}
-
-reseeding_bytes!(reseeding_chacha20_4k, 4);
-reseeding_bytes!(reseeding_chacha20_16k, 16);
-reseeding_bytes!(reseeding_chacha20_32k, 32);
-reseeding_bytes!(reseeding_chacha20_64k, 64);
-reseeding_bytes!(reseeding_chacha20_256k, 256);
-reseeding_bytes!(reseeding_chacha20_1M, 1024);
-
-
-macro_rules! threadrng_uint {
- ($fnn:ident, $ty:ty) => {
- #[bench]
- fn $fnn(b: &mut Bencher) {
- let mut rng = thread_rng();
- b.iter(|| {
- let mut accum: $ty = 0;
- for _ in 0..RAND_BENCH_N {
- accum = accum.wrapping_add(rng.gen::<$ty>());
- }
- accum
- });
- b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
- }
- };
-}
-
-threadrng_uint!(thread_rng_u32, u32);
-threadrng_uint!(thread_rng_u64, u64);
diff --git a/benches/misc.rs b/benches/misc.rs
deleted file mode 100644
index e46137f..0000000
--- a/benches/misc.rs
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(test)]
-
-extern crate test;
-
-const RAND_BENCH_N: u64 = 1000;
-
-use test::Bencher;
-
-use rand::distributions::{Bernoulli, Distribution, Standard};
-use rand::prelude::*;
-use rand_pcg::{Pcg32, Pcg64Mcg};
-
-#[bench]
-fn misc_gen_bool_const(b: &mut Bencher) {
- let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- let mut accum = true;
- for _ in 0..crate::RAND_BENCH_N {
- accum ^= rng.gen_bool(0.18);
- }
- accum
- })
-}
-
-#[bench]
-fn misc_gen_bool_var(b: &mut Bencher) {
- let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- let mut accum = true;
- let mut p = 0.18;
- for _ in 0..crate::RAND_BENCH_N {
- accum ^= rng.gen_bool(p);
- p += 0.0001;
- }
- accum
- })
-}
-
-#[bench]
-fn misc_gen_ratio_const(b: &mut Bencher) {
- let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- let mut accum = true;
- for _ in 0..crate::RAND_BENCH_N {
- accum ^= rng.gen_ratio(2, 3);
- }
- accum
- })
-}
-
-#[bench]
-fn misc_gen_ratio_var(b: &mut Bencher) {
- let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- let mut accum = true;
- for i in 2..(crate::RAND_BENCH_N as u32 + 2) {
- accum ^= rng.gen_ratio(i, i + 1);
- }
- accum
- })
-}
-
-#[bench]
-fn misc_bernoulli_const(b: &mut Bencher) {
- let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- let d = rand::distributions::Bernoulli::new(0.18).unwrap();
- let mut accum = true;
- for _ in 0..crate::RAND_BENCH_N {
- accum ^= rng.sample(d);
- }
- accum
- })
-}
-
-#[bench]
-fn misc_bernoulli_var(b: &mut Bencher) {
- let mut rng = Pcg32::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- let mut accum = true;
- let mut p = 0.18;
- for _ in 0..crate::RAND_BENCH_N {
- let d = Bernoulli::new(p).unwrap();
- accum ^= rng.sample(d);
- p += 0.0001;
- }
- accum
- })
-}
-
-#[bench]
-fn gen_1k_iter_repeat(b: &mut Bencher) {
- use std::iter;
- let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- let v: Vec<u64> = iter::repeat(()).map(|()| rng.gen()).take(128).collect();
- v
- });
- b.bytes = 1024;
-}
-
-#[bench]
-fn gen_1k_sample_iter(b: &mut Bencher) {
- let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- let v: Vec<u64> = Standard.sample_iter(&mut rng).take(128).collect();
- v
- });
- b.bytes = 1024;
-}
-
-#[bench]
-fn gen_1k_gen_array(b: &mut Bencher) {
- let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap();
- b.iter(|| {
- // max supported array length is 32!
- let v: [[u64; 32]; 4] = rng.gen();
- v
- });
- b.bytes = 1024;
-}
-
-#[bench]
-fn gen_1k_fill(b: &mut Bencher) {
- let mut rng = Pcg64Mcg::from_rng(&mut thread_rng()).unwrap();
- let mut buf = [0u64; 128];
- b.iter(|| {
- rng.fill(&mut buf[..]);
- buf
- });
- b.bytes = 1024;
-}
diff --git a/benches/seq.rs b/benches/seq.rs
deleted file mode 100644
index 7da2ff8..0000000
--- a/benches/seq.rs
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(test)]
-#![allow(non_snake_case)]
-
-extern crate test;
-
-use test::Bencher;
-
-use rand::prelude::*;
-use rand::seq::*;
-use std::mem::size_of;
-
-// We force use of 32-bit RNG since seq code is optimised for use with 32-bit
-// generators on all platforms.
-use rand_pcg::Pcg32 as SmallRng;
-
-const RAND_BENCH_N: u64 = 1000;
-
-#[bench]
-fn seq_shuffle_100(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- let x: &mut [usize] = &mut [1; 100];
- b.iter(|| {
- x.shuffle(&mut rng);
- x[0]
- })
-}
-
-#[bench]
-fn seq_slice_choose_1_of_1000(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- let x: &mut [usize] = &mut [1; 1000];
- for i in 0..1000 {
- x[i] = i;
- }
- b.iter(|| {
- let mut s = 0;
- for _ in 0..RAND_BENCH_N {
- s += x.choose(&mut rng).unwrap();
- }
- s
- });
- b.bytes = size_of::<usize>() as u64 * crate::RAND_BENCH_N;
-}
-
-macro_rules! seq_slice_choose_multiple {
- ($name:ident, $amount:expr, $length:expr) => {
- #[bench]
- fn $name(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- let x: &[i32] = &[$amount; $length];
- let mut result = [0i32; $amount];
- b.iter(|| {
- // Collect full result to prevent unwanted shortcuts getting
- // first element (in case sample_indices returns an iterator).
- for (slot, sample) in result.iter_mut().zip(x.choose_multiple(&mut rng, $amount)) {
- *slot = *sample;
- }
- result[$amount - 1]
- })
- }
- };
-}
-
-seq_slice_choose_multiple!(seq_slice_choose_multiple_1_of_1000, 1, 1000);
-seq_slice_choose_multiple!(seq_slice_choose_multiple_950_of_1000, 950, 1000);
-seq_slice_choose_multiple!(seq_slice_choose_multiple_10_of_100, 10, 100);
-seq_slice_choose_multiple!(seq_slice_choose_multiple_90_of_100, 90, 100);
-
-#[bench]
-fn seq_iter_choose_from_1000(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- let x: &mut [usize] = &mut [1; 1000];
- for i in 0..1000 {
- x[i] = i;
- }
- b.iter(|| {
- let mut s = 0;
- for _ in 0..RAND_BENCH_N {
- s += x.iter().choose(&mut rng).unwrap();
- }
- s
- });
- b.bytes = size_of::<usize>() as u64 * crate::RAND_BENCH_N;
-}
-
-#[derive(Clone)]
-struct UnhintedIterator<I: Iterator + Clone> {
- iter: I,
-}
-impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> {
- type Item = I::Item;
-
- fn next(&mut self) -> Option<Self::Item> {
- self.iter.next()
- }
-}
-
-#[derive(Clone)]
-struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> {
- iter: I,
- window_size: usize,
-}
-impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<I> {
- type Item = I::Item;
-
- fn next(&mut self) -> Option<Self::Item> {
- self.iter.next()
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- (std::cmp::min(self.iter.len(), self.window_size), None)
- }
-}
-
-#[bench]
-fn seq_iter_unhinted_choose_from_1000(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- let x: &[usize] = &[1; 1000];
- b.iter(|| {
- UnhintedIterator { iter: x.iter() }
- .choose(&mut rng)
- .unwrap()
- })
-}
-
-#[bench]
-fn seq_iter_window_hinted_choose_from_1000(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- let x: &[usize] = &[1; 1000];
- b.iter(|| {
- WindowHintedIterator {
- iter: x.iter(),
- window_size: 7,
- }
- .choose(&mut rng)
- })
-}
-
-#[bench]
-fn seq_iter_choose_multiple_10_of_100(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- let x: &[usize] = &[1; 100];
- b.iter(|| x.iter().cloned().choose_multiple(&mut rng, 10))
-}
-
-#[bench]
-fn seq_iter_choose_multiple_fill_10_of_100(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- let x: &[usize] = &[1; 100];
- let mut buf = [0; 10];
- b.iter(|| x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf))
-}
-
-macro_rules! sample_indices {
- ($name:ident, $fn:ident, $amount:expr, $length:expr) => {
- #[bench]
- fn $name(b: &mut Bencher) {
- let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
- b.iter(|| index::$fn(&mut rng, $length, $amount))
- }
- };
-}
-
-sample_indices!(misc_sample_indices_1_of_1k, sample, 1, 1000);
-sample_indices!(misc_sample_indices_10_of_1k, sample, 10, 1000);
-sample_indices!(misc_sample_indices_100_of_1k, sample, 100, 1000);
-sample_indices!(misc_sample_indices_100_of_1M, sample, 100, 1000_000);
-sample_indices!(misc_sample_indices_100_of_1G, sample, 100, 1000_000_000);
-sample_indices!(misc_sample_indices_200_of_1G, sample, 200, 1000_000_000);
-sample_indices!(misc_sample_indices_400_of_1G, sample, 400, 1000_000_000);
-sample_indices!(misc_sample_indices_600_of_1G, sample, 600, 1000_000_000);
diff --git a/benches/weighted.rs b/benches/weighted.rs
deleted file mode 100644
index 6872290..0000000
--- a/benches/weighted.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2019 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(test)]
-
-extern crate test;
-
-use rand::distributions::WeightedIndex;
-use rand::Rng;
-use test::Bencher;
-
-#[bench]
-fn weighted_index_creation(b: &mut Bencher) {
- let mut rng = rand::thread_rng();
- let weights = [1u32, 2, 4, 0, 5, 1, 7, 1, 2, 3, 4, 5, 6, 7];
- b.iter(|| {
- let distr = WeightedIndex::new(weights.to_vec()).unwrap();
- rng.sample(distr)
- })
-}
-
-#[bench]
-fn weighted_index_modification(b: &mut Bencher) {
- let mut rng = rand::thread_rng();
- let weights = [1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7];
- let mut distr = WeightedIndex::new(weights.to_vec()).unwrap();
- b.iter(|| {
- distr.update_weights(&[(2, &4), (5, &1)]).unwrap();
- rng.sample(&distr)
- })
-}
diff --git a/examples/monte-carlo.rs b/examples/monte-carlo.rs
deleted file mode 100644
index 70560d0..0000000
--- a/examples/monte-carlo.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013-2018 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! # Monte Carlo estimation of π
-//!
-//! Imagine that we have a square with sides of length 2 and a unit circle
-//! (radius = 1), both centered at the origin. The areas are:
-//!
-//! ```text
-//! area of circle = πr² = π * r * r = π
-//! area of square = 2² = 4
-//! ```
-//!
-//! The circle is entirely within the square, so if we sample many points
-//! randomly from the square, roughly π / 4 of them should be inside the circle.
-//!
-//! We can use the above fact to estimate the value of π: pick many points in
-//! the square at random, calculate the fraction that fall within the circle,
-//! and multiply this fraction by 4.
-
-#![cfg(feature = "std")]
-
-use rand::distributions::{Distribution, Uniform};
-
-fn main() {
- let range = Uniform::new(-1.0f64, 1.0);
- let mut rng = rand::thread_rng();
-
- let total = 1_000_000;
- let mut in_circle = 0;
-
- for _ in 0..total {
- let a = range.sample(&mut rng);
- let b = range.sample(&mut rng);
- if a * a + b * b <= 1.0 {
- in_circle += 1;
- }
- }
-
- // prints something close to 3.14159...
- println!(
- "π is approximately {}",
- 4. * (in_circle as f64) / (total as f64)
- );
-}
diff --git a/examples/monty-hall.rs b/examples/monty-hall.rs
deleted file mode 100644
index 30e2f44..0000000
--- a/examples/monty-hall.rs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013-2018 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! ## Monty Hall Problem
-//!
-//! This is a simulation of the [Monty Hall Problem][]:
-//!
-//! > Suppose you're on a game show, and you're given the choice of three doors:
-//! > Behind one door is a car; behind the others, goats. You pick a door, say
-//! > No. 1, and the host, who knows what's behind the doors, opens another
-//! > door, say No. 3, which has a goat. He then says to you, "Do you want to
-//! > pick door No. 2?" Is it to your advantage to switch your choice?
-//!
-//! The rather unintuitive answer is that you will have a 2/3 chance of winning
-//! if you switch and a 1/3 chance of winning if you don't, so it's better to
-//! switch.
-//!
-//! This program will simulate the game show and with large enough simulation
-//! steps it will indeed confirm that it is better to switch.
-//!
-//! [Monty Hall Problem]: https://en.wikipedia.org/wiki/Monty_Hall_problem
-
-#![cfg(feature = "std")]
-
-use rand::distributions::{Distribution, Uniform};
-use rand::Rng;
-
-struct SimulationResult {
- win: bool,
- switch: bool,
-}
-
-// Run a single simulation of the Monty Hall problem.
-fn simulate<R: Rng>(random_door: &Uniform<u32>, rng: &mut R) -> SimulationResult {
- let car = random_door.sample(rng);
-
- // This is our initial choice
- let mut choice = random_door.sample(rng);
-
- // The game host opens a door
- let open = game_host_open(car, choice, rng);
-
- // Shall we switch?
- let switch = rng.gen();
- if switch {
- choice = switch_door(choice, open);
- }
-
- SimulationResult {
- win: choice == car,
- switch,
- }
-}
-
-// Returns the door the game host opens given our choice and knowledge of
-// where the car is. The game host will never open the door with the car.
-fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 {
- use rand::seq::SliceRandom;
- *free_doors(&[car, choice]).choose(rng).unwrap()
-}
-
-// Returns the door we switch to, given our current choice and
-// the open door. There will only be one valid door.
-fn switch_door(choice: u32, open: u32) -> u32 {
- free_doors(&[choice, open])[0]
-}
-
-fn free_doors(blocked: &[u32]) -> Vec<u32> {
- (0..3).filter(|x| !blocked.contains(x)).collect()
-}
-
-fn main() {
- // The estimation will be more accurate with more simulations
- let num_simulations = 10000;
-
- let mut rng = rand::thread_rng();
- let random_door = Uniform::new(0u32, 3);
-
- let (mut switch_wins, mut switch_losses) = (0, 0);
- let (mut keep_wins, mut keep_losses) = (0, 0);
-
- println!("Running {} simulations...", num_simulations);
- for _ in 0..num_simulations {
- let result = simulate(&random_door, &mut rng);
-
- match (result.win, result.switch) {
- (true, true) => switch_wins += 1,
- (true, false) => keep_wins += 1,
- (false, true) => switch_losses += 1,
- (false, false) => keep_losses += 1,
- }
- }
-
- let total_switches = switch_wins + switch_losses;
- let total_keeps = keep_wins + keep_losses;
-
- println!(
- "Switched door {} times with {} wins and {} losses",
- total_switches, switch_wins, switch_losses
- );
-
- println!(
- "Kept our choice {} times with {} wins and {} losses",
- total_keeps, keep_wins, keep_losses
- );
-
- // With a large number of simulations, the values should converge to
- // 0.667 and 0.333 respectively.
- println!(
- "Estimated chance to win if we switch: {}",
- switch_wins as f32 / total_switches as f32
- );
- println!(
- "Estimated chance to win if we don't: {}",
- keep_wins as f32 / total_keeps as f32
- );
-}
diff --git a/rustfmt.toml b/rustfmt.toml
deleted file mode 100644
index 6a2d9d4..0000000
--- a/rustfmt.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-# This rustfmt file is added for configuration, but in practice much of our
-# code is hand-formatted, frequently with more readable results.
-
-# Comments:
-normalize_comments = true
-wrap_comments = false
-comment_width = 90 # small excess is okay but prefer 80
-
-# Arguments:
-use_small_heuristics = "Default"
-# TODO: single line functions only where short, please?
-# https://github.com/rust-lang/rustfmt/issues/3358
-fn_single_line = false
-fn_args_layout = "Compressed"
-overflow_delimited_expr = true
-where_single_line = true
-
-# enum_discrim_align_threshold = 20
-# struct_field_align_threshold = 20
-
-# Compatibility:
-edition = "2018" # we require compatibility back to 1.32.0
-
-# Misc:
-inline_attribute_width = 80
-blank_lines_upper_bound = 2
-reorder_impl_items = true
-# report_todo = "Unnumbered"
-# report_fixme = "Unnumbered"
-
-# Ignored files:
-ignore = []
diff --git a/src/distributions/bernoulli.rs b/src/distributions/bernoulli.rs
index a1fa86e..b968ca0 100644
--- a/src/distributions/bernoulli.rs
+++ b/src/distributions/bernoulli.rs
@@ -12,6 +12,8 @@
use crate::Rng;
use core::{fmt, u64};
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
/// The Bernoulli distribution.
///
/// This is a special case of the Binomial distribution where `n = 1`.
@@ -32,6 +34,7 @@
/// so only probabilities that are multiples of 2<sup>-64</sup> can be
/// represented.
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Bernoulli {
/// Probability of success, relative to the maximal integer.
p_int: u64,
@@ -144,6 +147,15 @@
use crate::Rng;
#[test]
+ #[cfg(feature="serde1")]
+ fn test_serializing_deserializing_bernoulli() {
+ let coin_flip = Bernoulli::new(0.5).unwrap();
+ let de_coin_flip : Bernoulli = bincode::deserialize(&bincode::serialize(&coin_flip).unwrap()).unwrap();
+
+ assert_eq!(coin_flip.p_int, de_coin_flip.p_int);
+ }
+
+ #[test]
fn test_trivial() {
let mut r = crate::test::rng(1);
let always_false = Bernoulli::new(0.0).unwrap();
diff --git a/src/distributions/binomial.rs b/src/distributions/binomial.rs
deleted file mode 100644
index c096e4a..0000000
--- a/src/distributions/binomial.rs
+++ /dev/null
@@ -1,321 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2016-2017 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The binomial distribution.
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::{Distribution, Uniform};
-use crate::Rng;
-
-/// The binomial distribution `Binomial(n, p)`.
-///
-/// This distribution has density function:
-/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Binomial {
- /// Number of trials.
- n: u64,
- /// Probability of success.
- p: f64,
-}
-
-impl Binomial {
- /// Construct a new `Binomial` with the given shape parameters `n` (number
- /// of trials) and `p` (probability of success).
- ///
- /// Panics if `p < 0` or `p > 1`.
- pub fn new(n: u64, p: f64) -> Binomial {
- assert!(p >= 0.0, "Binomial::new called with p < 0");
- assert!(p <= 1.0, "Binomial::new called with p > 1");
- Binomial { n, p }
- }
-}
-
-/// Convert a `f64` to an `i64`, panicing on overflow.
-// In the future (Rust 1.34), this might be replaced with `TryFrom`.
-fn f64_to_i64(x: f64) -> i64 {
- assert!(x < (::std::i64::MAX as f64));
- x as i64
-}
-
-impl Distribution<u64> for Binomial {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
- // Handle these values directly.
- if self.p == 0.0 {
- return 0;
- } else if self.p == 1.0 {
- return self.n;
- }
-
- // The binomial distribution is symmetrical with respect to p -> 1-p,
- // k -> n-k switch p so that it is less than 0.5 - this allows for lower
- // expected values we will just invert the result at the end
- let p = if self.p <= 0.5 { self.p } else { 1.0 - self.p };
-
- let result;
- let q = 1. - p;
-
- // For small n * min(p, 1 - p), the BINV algorithm based on the inverse
- // transformation of the binomial distribution is efficient. Otherwise,
- // the BTPE algorithm is used.
- //
- // Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial
- // random variate generation. Commun. ACM 31, 2 (February 1988),
- // 216-222. http://dx.doi.org/10.1145/42372.42381
-
- // Threshold for prefering the BINV algorithm. The paper suggests 10,
- // Ranlib uses 30, and GSL uses 14.
- const BINV_THRESHOLD: f64 = 10.;
-
- if (self.n as f64) * p < BINV_THRESHOLD && self.n <= (::std::i32::MAX as u64) {
- // Use the BINV algorithm.
- let s = p / q;
- let a = ((self.n + 1) as f64) * s;
- let mut r = q.powi(self.n as i32);
- let mut u: f64 = rng.gen();
- let mut x = 0;
- while u > r as f64 {
- u -= r;
- x += 1;
- r *= a / (x as f64) - s;
- }
- result = x;
- } else {
- // Use the BTPE algorithm.
-
- // Threshold for using the squeeze algorithm. This can be freely
- // chosen based on performance. Ranlib and GSL use 20.
- const SQUEEZE_THRESHOLD: i64 = 20;
-
- // Step 0: Calculate constants as functions of `n` and `p`.
- let n = self.n as f64;
- let np = n * p;
- let npq = np * q;
- let f_m = np + p;
- let m = f64_to_i64(f_m);
- // radius of triangle region, since height=1 also area of region
- let p1 = (2.195 * npq.sqrt() - 4.6 * q).floor() + 0.5;
- // tip of triangle
- let x_m = (m as f64) + 0.5;
- // left edge of triangle
- let x_l = x_m - p1;
- // right edge of triangle
- let x_r = x_m + p1;
- let c = 0.134 + 20.5 / (15.3 + (m as f64));
- // p1 + area of parallelogram region
- let p2 = p1 * (1. + 2. * c);
-
- fn lambda(a: f64) -> f64 {
- a * (1. + 0.5 * a)
- }
-
- let lambda_l = lambda((f_m - x_l) / (f_m - x_l * p));
- let lambda_r = lambda((x_r - f_m) / (x_r * q));
- // p1 + area of left tail
- let p3 = p2 + c / lambda_l;
- // p1 + area of right tail
- let p4 = p3 + c / lambda_r;
-
- // return value
- let mut y: i64;
-
- let gen_u = Uniform::new(0., p4);
- let gen_v = Uniform::new(0., 1.);
-
- loop {
- // Step 1: Generate `u` for selecting the region. If region 1 is
- // selected, generate a triangularly distributed variate.
- let u = gen_u.sample(rng);
- let mut v = gen_v.sample(rng);
- if !(u > p1) {
- y = f64_to_i64(x_m - p1 * v + u);
- break;
- }
-
- if !(u > p2) {
- // Step 2: Region 2, parallelograms. Check if region 2 is
- // used. If so, generate `y`.
- let x = x_l + (u - p1) / c;
- v = v * c + 1.0 - (x - x_m).abs() / p1;
- if v > 1. {
- continue;
- } else {
- y = f64_to_i64(x);
- }
- } else if !(u > p3) {
- // Step 3: Region 3, left exponential tail.
- y = f64_to_i64(x_l + v.ln() / lambda_l);
- if y < 0 {
- continue;
- } else {
- v *= (u - p2) * lambda_l;
- }
- } else {
- // Step 4: Region 4, right exponential tail.
- y = f64_to_i64(x_r - v.ln() / lambda_r);
- if y > 0 && (y as u64) > self.n {
- continue;
- } else {
- v *= (u - p3) * lambda_r;
- }
- }
-
- // Step 5: Acceptance/rejection comparison.
-
- // Step 5.0: Test for appropriate method of evaluating f(y).
- let k = (y - m).abs();
- if !(k > SQUEEZE_THRESHOLD && (k as f64) < 0.5 * npq - 1.) {
- // Step 5.1: Evaluate f(y) via the recursive relationship. Start the
- // search from the mode.
- let s = p / q;
- let a = s * (n + 1.);
- let mut f = 1.0;
- if m < y {
- let mut i = m;
- loop {
- i += 1;
- f *= a / (i as f64) - s;
- if i == y {
- break;
- }
- }
- } else if m > y {
- let mut i = y;
- loop {
- i += 1;
- f /= a / (i as f64) - s;
- if i == m {
- break;
- }
- }
- }
- if v > f {
- continue;
- } else {
- break;
- }
- }
-
- // Step 5.2: Squeezing. Check the value of ln(v) againts upper and
- // lower bound of ln(f(y)).
- let k = k as f64;
- let rho = (k / npq) * ((k * (k / 3. + 0.625) + 1. / 6.) / npq + 0.5);
- let t = -0.5 * k * k / npq;
- let alpha = v.ln();
- if alpha < t - rho {
- break;
- }
- if alpha > t + rho {
- continue;
- }
-
- // Step 5.3: Final acceptance/rejection test.
- let x1 = (y + 1) as f64;
- let f1 = (m + 1) as f64;
- let z = (f64_to_i64(n) + 1 - m) as f64;
- let w = (f64_to_i64(n) - y + 1) as f64;
-
- fn stirling(a: f64) -> f64 {
- let a2 = a * a;
- (13860. - (462. - (132. - (99. - 140. / a2) / a2) / a2) / a2) / a / 166320.
- }
-
- if alpha
- > x_m * (f1 / x1).ln()
- + (n - (m as f64) + 0.5) * (z / w).ln()
- + ((y - m) as f64) * (w * p / (x1 * q)).ln()
- // We use the signs from the GSL implementation, which are
- // different than the ones in the reference. According to
- // the GSL authors, the new signs were verified to be
- // correct by one of the original designers of the
- // algorithm.
- + stirling(f1)
- + stirling(z)
- - stirling(x1)
- - stirling(w)
- {
- continue;
- }
-
- break;
- }
- assert!(y >= 0);
- result = y as u64;
- }
-
- // Invert the result for p < 0.5.
- if p != self.p {
- self.n - result
- } else {
- result
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::Binomial;
- use crate::distributions::Distribution;
- use crate::Rng;
-
- fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) {
- let binomial = Binomial::new(n, p);
-
- let expected_mean = n as f64 * p;
- let expected_variance = n as f64 * p * (1.0 - p);
-
- let mut results = [0.0; 1000];
- for i in results.iter_mut() {
- *i = binomial.sample(rng) as f64;
- }
-
- let mean = results.iter().sum::<f64>() / results.len() as f64;
- assert!(
- (mean as f64 - expected_mean).abs() < expected_mean / 50.0,
- "mean: {}, expected_mean: {}",
- mean,
- expected_mean
- );
-
- let variance =
- results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>() / results.len() as f64;
- assert!(
- (variance - expected_variance).abs() < expected_variance / 10.0,
- "variance: {}, expected_variance: {}",
- variance,
- expected_variance
- );
- }
-
- #[test]
- #[cfg_attr(miri, ignore)] // Miri is too slow
- fn test_binomial() {
- let mut rng = crate::test::rng(351);
- test_binomial_mean_and_variance(150, 0.1, &mut rng);
- test_binomial_mean_and_variance(70, 0.6, &mut rng);
- test_binomial_mean_and_variance(40, 0.5, &mut rng);
- test_binomial_mean_and_variance(20, 0.7, &mut rng);
- test_binomial_mean_and_variance(20, 0.5, &mut rng);
- }
-
- #[test]
- fn test_binomial_end_points() {
- let mut rng = crate::test::rng(352);
- assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0);
- assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20);
- }
-
- #[test]
- #[should_panic]
- fn test_binomial_invalid_lambda_neg() {
- Binomial::new(20, -10.0);
- }
-}
diff --git a/src/distributions/cauchy.rs b/src/distributions/cauchy.rs
deleted file mode 100644
index dc54c98..0000000
--- a/src/distributions/cauchy.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2016-2017 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Cauchy distribution.
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::Distribution;
-use crate::Rng;
-use std::f64::consts::PI;
-
-/// The Cauchy distribution `Cauchy(median, scale)`.
-///
-/// This distribution has a density function:
-/// `f(x) = 1 / (pi * scale * (1 + ((x - median) / scale)^2))`
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Cauchy {
- median: f64,
- scale: f64,
-}
-
-impl Cauchy {
- /// Construct a new `Cauchy` with the given shape parameters
- /// `median` the peak location and `scale` the scale factor.
- /// Panics if `scale <= 0`.
- pub fn new(median: f64, scale: f64) -> Cauchy {
- assert!(scale > 0.0, "Cauchy::new called with scale factor <= 0");
- Cauchy { median, scale }
- }
-}
-
-impl Distribution<f64> for Cauchy {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- // sample from [0, 1)
- let x = rng.gen::<f64>();
- // get standard cauchy random number
- // note that π/2 is not exactly representable, even if x=0.5 the result is finite
- let comp_dev = (PI * x).tan();
- // shift and scale according to parameters
- let result = self.median + self.scale * comp_dev;
- result
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::Cauchy;
- use crate::distributions::Distribution;
-
- fn median(mut numbers: &mut [f64]) -> f64 {
- sort(&mut numbers);
- let mid = numbers.len() / 2;
- numbers[mid]
- }
-
- fn sort(numbers: &mut [f64]) {
- numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
- }
-
- #[test]
- fn test_cauchy_averages() {
- // NOTE: given that the variance and mean are undefined,
- // this test does not have any rigorous statistical meaning.
- let cauchy = Cauchy::new(10.0, 5.0);
- let mut rng = crate::test::rng(123);
- let mut numbers: [f64; 1000] = [0.0; 1000];
- let mut sum = 0.0;
- for i in 0..1000 {
- numbers[i] = cauchy.sample(&mut rng);
- sum += numbers[i];
- }
- let median = median(&mut numbers);
- println!("Cauchy median: {}", median);
- assert!((median - 10.0).abs() < 0.4); // not 100% certain, but probable enough
- let mean = sum / 1000.0;
- println!("Cauchy mean: {}", mean);
- // for a Cauchy distribution the mean should not converge
- assert!((mean - 10.0).abs() > 0.4); // not 100% certain, but probable enough
- }
-
- #[test]
- #[should_panic]
- fn test_cauchy_invalid_scale_zero() {
- Cauchy::new(0.0, 0.0);
- }
-
- #[test]
- #[should_panic]
- fn test_cauchy_invalid_scale_neg() {
- Cauchy::new(0.0, -10.0);
- }
-}
diff --git a/src/distributions/dirichlet.rs b/src/distributions/dirichlet.rs
deleted file mode 100644
index a75678a..0000000
--- a/src/distributions/dirichlet.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The dirichlet distribution.
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::gamma::Gamma;
-use crate::distributions::Distribution;
-use crate::Rng;
-
-/// The dirichelet distribution `Dirichlet(alpha)`.
-///
-/// The Dirichlet distribution is a family of continuous multivariate
-/// probability distributions parameterized by a vector alpha of positive reals.
-/// It is a multivariate generalization of the beta distribution.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Debug)]
-pub struct Dirichlet {
- /// Concentration parameters (alpha)
- alpha: Vec<f64>,
-}
-
-impl Dirichlet {
- /// Construct a new `Dirichlet` with the given alpha parameter `alpha`.
- ///
- /// # Panics
- /// - if `alpha.len() < 2`
- #[inline]
- pub fn new<V: Into<Vec<f64>>>(alpha: V) -> Dirichlet {
- let a = alpha.into();
- assert!(a.len() > 1);
- for i in 0..a.len() {
- assert!(a[i] > 0.0);
- }
-
- Dirichlet { alpha: a }
- }
-
- /// Construct a new `Dirichlet` with the given shape parameter `alpha` and `size`.
- ///
- /// # Panics
- /// - if `alpha <= 0.0`
- /// - if `size < 2`
- #[inline]
- pub fn new_with_param(alpha: f64, size: usize) -> Dirichlet {
- assert!(alpha > 0.0);
- assert!(size > 1);
- Dirichlet {
- alpha: vec![alpha; size],
- }
- }
-}
-
-impl Distribution<Vec<f64>> for Dirichlet {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<f64> {
- let n = self.alpha.len();
- let mut samples = vec![0.0f64; n];
- let mut sum = 0.0f64;
-
- for i in 0..n {
- let g = Gamma::new(self.alpha[i], 1.0);
- samples[i] = g.sample(rng);
- sum += samples[i];
- }
- let invacc = 1.0 / sum;
- for i in 0..n {
- samples[i] *= invacc;
- }
- samples
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::Dirichlet;
- use crate::distributions::Distribution;
-
- #[test]
- fn test_dirichlet() {
- let d = Dirichlet::new(vec![1.0, 2.0, 3.0]);
- let mut rng = crate::test::rng(221);
- let samples = d.sample(&mut rng);
- let _: Vec<f64> = samples
- .into_iter()
- .map(|x| {
- assert!(x > 0.0);
- x
- })
- .collect();
- }
-
- #[test]
- fn test_dirichlet_with_param() {
- let alpha = 0.5f64;
- let size = 2;
- let d = Dirichlet::new_with_param(alpha, size);
- let mut rng = crate::test::rng(221);
- let samples = d.sample(&mut rng);
- let _: Vec<f64> = samples
- .into_iter()
- .map(|x| {
- assert!(x > 0.0);
- x
- })
- .collect();
- }
-
- #[test]
- #[should_panic]
- fn test_dirichlet_invalid_length() {
- Dirichlet::new_with_param(0.5f64, 1);
- }
-
- #[test]
- #[should_panic]
- fn test_dirichlet_invalid_alpha() {
- Dirichlet::new_with_param(0.0f64, 2);
- }
-}
diff --git a/src/distributions/exponential.rs b/src/distributions/exponential.rs
deleted file mode 100644
index 5fdf7aa..0000000
--- a/src/distributions/exponential.rs
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The exponential distribution.
-#![allow(deprecated)]
-
-use crate::distributions::utils::ziggurat;
-use crate::distributions::{ziggurat_tables, Distribution};
-use crate::Rng;
-
-/// Samples floating-point numbers according to the exponential distribution,
-/// with rate parameter `λ = 1`. This is equivalent to `Exp::new(1.0)` or
-/// sampling with `-rng.gen::<f64>().ln()`, but faster.
-///
-/// See `Exp` for the general exponential distribution.
-///
-/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method. The exact
-/// description in the paper was adjusted to use tables for the exponential
-/// distribution rather than normal.
-///
-/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
-/// Generate Normal Random Samples*](
-/// https://www.doornik.com/research/ziggurat.pdf).
-/// Nuffield College, Oxford
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Exp1;
-
-// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
-impl Distribution<f64> for Exp1 {
- #[inline]
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- #[inline]
- fn pdf(x: f64) -> f64 {
- (-x).exp()
- }
- #[inline]
- fn zero_case<R: Rng + ?Sized>(rng: &mut R, _u: f64) -> f64 {
- ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
- }
-
- ziggurat(
- rng,
- false,
- &ziggurat_tables::ZIG_EXP_X,
- &ziggurat_tables::ZIG_EXP_F,
- pdf,
- zero_case,
- )
- }
-}
-
-/// The exponential distribution `Exp(lambda)`.
-///
-/// This distribution has density function: `f(x) = lambda * exp(-lambda * x)`
-/// for `x > 0`.
-///
-/// Note that [`Exp1`](crate::distributions::Exp1) is an optimised implementation for `lambda = 1`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Exp {
- /// `lambda` stored as `1/lambda`, since this is what we scale by.
- lambda_inverse: f64,
-}
-
-impl Exp {
- /// Construct a new `Exp` with the given shape parameter
- /// `lambda`. Panics if `lambda <= 0`.
- #[inline]
- pub fn new(lambda: f64) -> Exp {
- assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
- Exp {
- lambda_inverse: 1.0 / lambda,
- }
- }
-}
-
-impl Distribution<f64> for Exp {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- let n: f64 = rng.sample(Exp1);
- n * self.lambda_inverse
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::Exp;
- use crate::distributions::Distribution;
-
- #[test]
- fn test_exp() {
- let exp = Exp::new(10.0);
- let mut rng = crate::test::rng(221);
- for _ in 0..1000 {
- assert!(exp.sample(&mut rng) >= 0.0);
- }
- }
- #[test]
- #[should_panic]
- fn test_exp_invalid_lambda_zero() {
- Exp::new(0.0);
- }
- #[test]
- #[should_panic]
- fn test_exp_invalid_lambda_neg() {
- Exp::new(-10.0);
- }
-}
diff --git a/src/distributions/float.rs b/src/distributions/float.rs
index 0a45f39..733a403 100644
--- a/src/distributions/float.rs
+++ b/src/distributions/float.rs
@@ -14,6 +14,9 @@
use core::mem;
#[cfg(feature = "simd_support")] use packed_simd::*;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// A distribution to sample floating point numbers uniformly in the half-open
/// interval `(0, 1]`, i.e. including 1 but not 0.
///
@@ -39,6 +42,7 @@
/// [`Open01`]: crate::distributions::Open01
/// [`Uniform`]: crate::distributions::uniform::Uniform
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct OpenClosed01;
/// A distribution to sample floating point numbers uniformly in the open
@@ -65,6 +69,7 @@
/// [`OpenClosed01`]: crate::distributions::OpenClosed01
/// [`Uniform`]: crate::distributions::uniform::Uniform
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Open01;
diff --git a/src/distributions/gamma.rs b/src/distributions/gamma.rs
deleted file mode 100644
index f19738d..0000000
--- a/src/distributions/gamma.rs
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Gamma and derived distributions.
-#![allow(deprecated)]
-
-use self::ChiSquaredRepr::*;
-use self::GammaRepr::*;
-
-use crate::distributions::normal::StandardNormal;
-use crate::distributions::{Distribution, Exp, Open01};
-use crate::Rng;
-
-/// The Gamma distribution `Gamma(shape, scale)` distribution.
-///
-/// The density function of this distribution is
-///
-/// ```text
-/// f(x) = x^(k - 1) * exp(-x / θ) / (Γ(k) * θ^k)
-/// ```
-///
-/// where `Γ` is the Gamma function, `k` is the shape and `θ` is the
-/// scale and both `k` and `θ` are strictly positive.
-///
-/// The algorithm used is that described by Marsaglia & Tsang 2000[^1],
-/// falling back to directly sampling from an Exponential for `shape
-/// == 1`, and using the boosting technique described in that paper for
-/// `shape < 1`.
-///
-/// [^1]: George Marsaglia and Wai Wan Tsang. 2000. "A Simple Method for
-/// Generating Gamma Variables" *ACM Trans. Math. Softw.* 26, 3
-/// (September 2000), 363-372.
-/// DOI:[10.1145/358407.358414](https://doi.acm.org/10.1145/358407.358414)
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Gamma {
- repr: GammaRepr,
-}
-
-#[derive(Clone, Copy, Debug)]
-enum GammaRepr {
- Large(GammaLargeShape),
- One(Exp),
- Small(GammaSmallShape),
-}
-
-// These two helpers could be made public, but saving the
-// match-on-Gamma-enum branch from using them directly (e.g. if one
-// knows that the shape is always > 1) doesn't appear to be much
-// faster.
-
-/// Gamma distribution where the shape parameter is less than 1.
-///
-/// Note, samples from this require a compulsory floating-point `pow`
-/// call, which makes it significantly slower than sampling from a
-/// gamma distribution where the shape parameter is greater than or
-/// equal to 1.
-///
-/// See `Gamma` for sampling from a Gamma distribution with general
-/// shape parameters.
-#[derive(Clone, Copy, Debug)]
-struct GammaSmallShape {
- inv_shape: f64,
- large_shape: GammaLargeShape,
-}
-
-/// Gamma distribution where the shape parameter is larger than 1.
-///
-/// See `Gamma` for sampling from a Gamma distribution with general
-/// shape parameters.
-#[derive(Clone, Copy, Debug)]
-struct GammaLargeShape {
- scale: f64,
- c: f64,
- d: f64,
-}
-
-impl Gamma {
- /// Construct an object representing the `Gamma(shape, scale)`
- /// distribution.
- ///
- /// Panics if `shape <= 0` or `scale <= 0`.
- #[inline]
- pub fn new(shape: f64, scale: f64) -> Gamma {
- assert!(shape > 0.0, "Gamma::new called with shape <= 0");
- assert!(scale > 0.0, "Gamma::new called with scale <= 0");
-
- let repr = if shape == 1.0 {
- One(Exp::new(1.0 / scale))
- } else if shape < 1.0 {
- Small(GammaSmallShape::new_raw(shape, scale))
- } else {
- Large(GammaLargeShape::new_raw(shape, scale))
- };
- Gamma { repr }
- }
-}
-
-impl GammaSmallShape {
- fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
- GammaSmallShape {
- inv_shape: 1. / shape,
- large_shape: GammaLargeShape::new_raw(shape + 1.0, scale),
- }
- }
-}
-
-impl GammaLargeShape {
- fn new_raw(shape: f64, scale: f64) -> GammaLargeShape {
- let d = shape - 1. / 3.;
- GammaLargeShape {
- scale,
- c: 1. / (9. * d).sqrt(),
- d,
- }
- }
-}
-
-impl Distribution<f64> for Gamma {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- match self.repr {
- Small(ref g) => g.sample(rng),
- One(ref g) => g.sample(rng),
- Large(ref g) => g.sample(rng),
- }
- }
-}
-impl Distribution<f64> for GammaSmallShape {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- let u: f64 = rng.sample(Open01);
-
- self.large_shape.sample(rng) * u.powf(self.inv_shape)
- }
-}
-impl Distribution<f64> for GammaLargeShape {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- loop {
- let x = rng.sample(StandardNormal);
- let v_cbrt = 1.0 + self.c * x;
- if v_cbrt <= 0.0 {
- // a^3 <= 0 iff a <= 0
- continue;
- }
-
- let v = v_cbrt * v_cbrt * v_cbrt;
- let u: f64 = rng.sample(Open01);
-
- let x_sqr = x * x;
- if u < 1.0 - 0.0331 * x_sqr * x_sqr
- || u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln())
- {
- return self.d * v * self.scale;
- }
- }
- }
-}
-
-/// The chi-squared distribution `χ²(k)`, where `k` is the degrees of
-/// freedom.
-///
-/// For `k > 0` integral, this distribution is the sum of the squares
-/// of `k` independent standard normal random variables. For other
-/// `k`, this uses the equivalent characterisation
-/// `χ²(k) = Gamma(k/2, 2)`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct ChiSquared {
- repr: ChiSquaredRepr,
-}
-
-#[derive(Clone, Copy, Debug)]
-enum ChiSquaredRepr {
- // k == 1, Gamma(alpha, ..) is particularly slow for alpha < 1,
- // e.g. when alpha = 1/2 as it would be for this case, so special-
- // casing and using the definition of N(0,1)^2 is faster.
- DoFExactlyOne,
- DoFAnythingElse(Gamma),
-}
-
-impl ChiSquared {
- /// Create a new chi-squared distribution with degrees-of-freedom
- /// `k`. Panics if `k < 0`.
- pub fn new(k: f64) -> ChiSquared {
- let repr = if k == 1.0 {
- DoFExactlyOne
- } else {
- assert!(k > 0.0, "ChiSquared::new called with `k` < 0");
- DoFAnythingElse(Gamma::new(0.5 * k, 2.0))
- };
- ChiSquared { repr }
- }
-}
-impl Distribution<f64> for ChiSquared {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- match self.repr {
- DoFExactlyOne => {
- // k == 1 => N(0,1)^2
- let norm = rng.sample(StandardNormal);
- norm * norm
- }
- DoFAnythingElse(ref g) => g.sample(rng),
- }
- }
-}
-
-/// The Fisher F distribution `F(m, n)`.
-///
-/// This distribution is equivalent to the ratio of two normalised
-/// chi-squared distributions, that is, `F(m,n) = (χ²(m)/m) /
-/// (χ²(n)/n)`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct FisherF {
- numer: ChiSquared,
- denom: ChiSquared,
- // denom_dof / numer_dof so that this can just be a straight
- // multiplication, rather than a division.
- dof_ratio: f64,
-}
-
-impl FisherF {
- /// Create a new `FisherF` distribution, with the given
- /// parameter. Panics if either `m` or `n` are not positive.
- pub fn new(m: f64, n: f64) -> FisherF {
- assert!(m > 0.0, "FisherF::new called with `m < 0`");
- assert!(n > 0.0, "FisherF::new called with `n < 0`");
-
- FisherF {
- numer: ChiSquared::new(m),
- denom: ChiSquared::new(n),
- dof_ratio: n / m,
- }
- }
-}
-impl Distribution<f64> for FisherF {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- self.numer.sample(rng) / self.denom.sample(rng) * self.dof_ratio
- }
-}
-
-/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
-/// freedom.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct StudentT {
- chi: ChiSquared,
- dof: f64,
-}
-
-impl StudentT {
- /// Create a new Student t distribution with `n` degrees of
- /// freedom. Panics if `n <= 0`.
- pub fn new(n: f64) -> StudentT {
- assert!(n > 0.0, "StudentT::new called with `n <= 0`");
- StudentT {
- chi: ChiSquared::new(n),
- dof: n,
- }
- }
-}
-impl Distribution<f64> for StudentT {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- let norm = rng.sample(StandardNormal);
- norm * (self.dof / self.chi.sample(rng)).sqrt()
- }
-}
-
-/// The Beta distribution with shape parameters `alpha` and `beta`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Beta {
- gamma_a: Gamma,
- gamma_b: Gamma,
-}
-
-impl Beta {
- /// Construct an object representing the `Beta(alpha, beta)`
- /// distribution.
- ///
- /// Panics if `shape <= 0` or `scale <= 0`.
- pub fn new(alpha: f64, beta: f64) -> Beta {
- assert!((alpha > 0.) & (beta > 0.));
- Beta {
- gamma_a: Gamma::new(alpha, 1.),
- gamma_b: Gamma::new(beta, 1.),
- }
- }
-}
-
-impl Distribution<f64> for Beta {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- let x = self.gamma_a.sample(rng);
- let y = self.gamma_b.sample(rng);
- x / (x + y)
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::{Beta, ChiSquared, FisherF, StudentT};
- use crate::distributions::Distribution;
-
- const N: u32 = 100;
-
- #[test]
- fn test_chi_squared_one() {
- let chi = ChiSquared::new(1.0);
- let mut rng = crate::test::rng(201);
- for _ in 0..N {
- chi.sample(&mut rng);
- }
- }
- #[test]
- fn test_chi_squared_small() {
- let chi = ChiSquared::new(0.5);
- let mut rng = crate::test::rng(202);
- for _ in 0..N {
- chi.sample(&mut rng);
- }
- }
- #[test]
- fn test_chi_squared_large() {
- let chi = ChiSquared::new(30.0);
- let mut rng = crate::test::rng(203);
- for _ in 0..N {
- chi.sample(&mut rng);
- }
- }
- #[test]
- #[should_panic]
- fn test_chi_squared_invalid_dof() {
- ChiSquared::new(-1.0);
- }
-
- #[test]
- fn test_f() {
- let f = FisherF::new(2.0, 32.0);
- let mut rng = crate::test::rng(204);
- for _ in 0..N {
- f.sample(&mut rng);
- }
- }
-
- #[test]
- fn test_t() {
- let t = StudentT::new(11.0);
- let mut rng = crate::test::rng(205);
- for _ in 0..N {
- t.sample(&mut rng);
- }
- }
-
- #[test]
- fn test_beta() {
- let beta = Beta::new(1.0, 2.0);
- let mut rng = crate::test::rng(201);
- for _ in 0..N {
- beta.sample(&mut rng);
- }
- }
-
- #[test]
- #[should_panic]
- fn test_beta_invalid_dof() {
- Beta::new(0., 0.);
- }
-}
diff --git a/src/distributions/integer.rs b/src/distributions/integer.rs
index f2db1f1..8a2ce4c 100644
--- a/src/distributions/integer.rs
+++ b/src/distributions/integer.rs
@@ -10,9 +10,10 @@
use crate::distributions::{Distribution, Standard};
use crate::Rng;
-#[cfg(all(target_arch = "x86", feature = "nightly"))] use core::arch::x86::*;
-#[cfg(all(target_arch = "x86_64", feature = "nightly"))]
-use core::arch::x86_64::*;
+#[cfg(all(target_arch = "x86", feature = "simd_support"))]
+use core::arch::x86::{__m128i, __m256i};
+#[cfg(all(target_arch = "x86_64", feature = "simd_support"))]
+use core::arch::x86_64::{__m128i, __m256i};
#[cfg(not(target_os = "emscripten"))] use core::num::NonZeroU128;
use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
#[cfg(feature = "simd_support")] use packed_simd::*;
@@ -155,10 +156,9 @@
simd_impl!(512, u8x64, i8x64, u16x32, i16x32, u32x16, i32x16, u64x8, i64x8,);
#[cfg(all(
feature = "simd_support",
- feature = "nightly",
any(target_arch = "x86", target_arch = "x86_64")
))]
-simd_impl!((__m64, u8x8), (__m128i, u8x16), (__m256i, u8x32),);
+simd_impl!((__m128i, u8x16), (__m256i, u8x32),);
#[cfg(test)]
mod tests {
diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs
index 4e1b1a6..652f52a 100644
--- a/src/distributions/mod.rs
+++ b/src/distributions/mod.rs
@@ -11,11 +11,11 @@
//!
//! This module is the home of the [`Distribution`] trait and several of its
//! implementations. It is the workhorse behind some of the convenient
-//! functionality of the [`Rng`] trait, e.g. [`Rng::gen`], [`Rng::gen_range`] and
-//! of course [`Rng::sample`].
+//! functionality of the [`Rng`] trait, e.g. [`Rng::gen`] and of course
+//! [`Rng::sample`].
//!
//! Abstractly, a [probability distribution] describes the probability of
-//! occurance of each value in its sample space.
+//! occurrence of each value in its sample space.
//!
//! More concretely, an implementation of `Distribution<T>` for type `X` is an
//! algorithm for choosing values from the sample space (a subset of `T`)
@@ -54,16 +54,16 @@
//! space to be specified as an arbitrary range within its target type `T`.
//! Both [`Standard`] and [`Uniform`] are in some sense uniform distributions.
//!
-//! Values may be sampled from this distribution using [`Rng::gen_range`] or
+//! Values may be sampled from this distribution using [`Rng::sample(Range)`] or
//! by creating a distribution object with [`Uniform::new`],
//! [`Uniform::new_inclusive`] or `From<Range>`. When the range limits are not
//! known at compile time it is typically faster to reuse an existing
-//! distribution object than to call [`Rng::gen_range`].
+//! `Uniform` object than to call [`Rng::sample(Range)`].
//!
//! User types `T` may also implement `Distribution<T>` for [`Uniform`],
//! although this is less straightforward than for [`Standard`] (see the
-//! documentation in the [`uniform`] module. Doing so enables generation of
-//! values of type `T` with [`Rng::gen_range`].
+//! documentation in the [`uniform`] module). Doing so enables generation of
+//! values of type `T` with [`Rng::sample(Range)`].
//!
//! ## Open and half-open ranges
//!
@@ -79,7 +79,7 @@
//! the [`Bernoulli`] distribution (this is used by [`Rng::gen_bool`]).
//!
//! For weighted sampling from a sequence of discrete values, use the
-//! [`weighted`] module.
+//! [`WeightedIndex`] distribution.
//!
//! This crate no longer includes other non-uniform distributions; instead
//! it is recommended that you use either [`rand_distr`] or [`statrs`].
@@ -100,62 +100,21 @@
pub use self::float::{Open01, OpenClosed01};
pub use self::other::Alphanumeric;
#[doc(inline)] pub use self::uniform::Uniform;
-#[cfg(feature = "alloc")]
-pub use self::weighted::{WeightedError, WeightedIndex};
-// The following are all deprecated after being moved to rand_distr
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::binomial::Binomial;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::cauchy::Cauchy;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::dirichlet::Dirichlet;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::exponential::{Exp, Exp1};
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::gamma::{Beta, ChiSquared, FisherF, Gamma, StudentT};
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::normal::{LogNormal, Normal, StandardNormal};
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::pareto::Pareto;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::poisson::Poisson;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::triangular::Triangular;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::unit_circle::UnitCircle;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::unit_sphere::UnitSphereSurface;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::weibull::Weibull;
+#[cfg(feature = "alloc")]
+pub use self::weighted_index::{WeightedError, WeightedIndex};
mod bernoulli;
-#[cfg(feature = "std")] mod binomial;
-#[cfg(feature = "std")] mod cauchy;
-#[cfg(feature = "std")] mod dirichlet;
-#[cfg(feature = "std")] mod exponential;
-#[cfg(feature = "std")] mod gamma;
-#[cfg(feature = "std")] mod normal;
-#[cfg(feature = "std")] mod pareto;
-#[cfg(feature = "std")] mod poisson;
-#[cfg(feature = "std")] mod triangular;
pub mod uniform;
-#[cfg(feature = "std")] mod unit_circle;
-#[cfg(feature = "std")] mod unit_sphere;
-#[cfg(feature = "std")] mod weibull;
-#[cfg(feature = "alloc")] pub mod weighted;
+
+#[deprecated(since = "0.8.0", note = "use rand::distributions::{WeightedIndex, WeightedError} instead")]
+#[cfg(feature = "alloc")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+pub mod weighted;
+#[cfg(feature = "alloc")] mod weighted_index;
+
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
mod float;
#[doc(hidden)]
@@ -165,7 +124,6 @@
mod integer;
mod other;
mod utils;
-#[cfg(feature = "std")] mod ziggurat_tables;
/// Types (distributions) that can be used to create a random instance of `T`.
///
@@ -204,17 +162,21 @@
/// use rand::thread_rng;
/// use rand::distributions::{Distribution, Alphanumeric, Uniform, Standard};
///
- /// let rng = thread_rng();
+ /// let mut rng = thread_rng();
///
/// // Vec of 16 x f32:
- /// let v: Vec<f32> = Standard.sample_iter(rng).take(16).collect();
+ /// let v: Vec<f32> = Standard.sample_iter(&mut rng).take(16).collect();
///
/// // String:
- /// let s: String = Alphanumeric.sample_iter(rng).take(7).collect();
+ /// let s: String = Alphanumeric
+ /// .sample_iter(&mut rng)
+ /// .take(7)
+ /// .map(char::from)
+ /// .collect();
///
/// // Dice-rolling:
/// let die_range = Uniform::new_inclusive(1, 6);
- /// let mut roll_die = die_range.sample_iter(rng);
+ /// let mut roll_die = die_range.sample_iter(&mut rng);
/// while roll_die.next().unwrap() != 6 {
/// println!("Not a 6; rolling again!");
/// }
@@ -359,18 +321,18 @@
/// multiplicative method: `(rng.gen::<$uty>() >> N) as $ty * (ε/2)`.
///
/// See also: [`Open01`] which samples from `(0, 1)`, [`OpenClosed01`] which
-/// samples from `(0, 1]` and `Rng::gen_range(0, 1)` which also samples from
-/// `[0, 1)`. Note that `Open01` and `gen_range` (which uses [`Uniform`]) use
-/// transmute-based methods which yield 1 bit less precision but may perform
-/// faster on some architectures (on modern Intel CPUs all methods have
-/// approximately equal performance).
+/// samples from `(0, 1]` and `Rng::gen_range(0..1)` which also samples from
+/// `[0, 1)`. Note that `Open01` uses transmute-based methods which yield 1 bit
+/// less precision but may perform faster on some architectures (on modern Intel
+/// CPUs all methods have approximately equal performance).
///
/// [`Uniform`]: uniform::Uniform
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Standard;
-#[cfg(all(test, feature = "std"))]
+#[cfg(test)]
mod tests {
use super::{Distribution, Uniform};
use crate::Rng;
@@ -380,8 +342,12 @@
use crate::distributions::Open01;
let mut rng = crate::test::rng(210);
let distr = Open01;
- let results: Vec<f32> = distr.sample_iter(&mut rng).take(100).collect();
- println!("{:?}", results);
+ let mut iter = Distribution::<f32>::sample_iter(distr, &mut rng);
+ let mut sum: f32 = 0.;
+ for _ in 0..100 {
+ sum += iter.next().unwrap();
+ }
+ assert!(0. < sum && sum < 100.);
}
#[test]
diff --git a/src/distributions/normal.rs b/src/distributions/normal.rs
deleted file mode 100644
index ec62fa9..0000000
--- a/src/distributions/normal.rs
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The normal and derived distributions.
-#![allow(deprecated)]
-
-use crate::distributions::utils::ziggurat;
-use crate::distributions::{ziggurat_tables, Distribution, Open01};
-use crate::Rng;
-
-/// Samples floating-point numbers according to the normal distribution
-/// `N(0, 1)` (a.k.a. a standard normal, or Gaussian). This is equivalent to
-/// `Normal::new(0.0, 1.0)` but faster.
-///
-/// See `Normal` for the general normal distribution.
-///
-/// Implemented via the ZIGNOR variant[^1] of the Ziggurat method.
-///
-/// [^1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
-/// Generate Normal Random Samples*](
-/// https://www.doornik.com/research/ziggurat.pdf).
-/// Nuffield College, Oxford
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct StandardNormal;
-
-impl Distribution<f64> for StandardNormal {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- #[inline]
- fn pdf(x: f64) -> f64 {
- (-x * x / 2.0).exp()
- }
- #[inline]
- fn zero_case<R: Rng + ?Sized>(rng: &mut R, u: f64) -> f64 {
- // compute a random number in the tail by hand
-
- // strange initial conditions, because the loop is not
- // do-while, so the condition should be true on the first
- // run, they get overwritten anyway (0 < 1, so these are
- // good).
- let mut x = 1.0f64;
- let mut y = 0.0f64;
-
- while -2.0 * y < x * x {
- let x_: f64 = rng.sample(Open01);
- let y_: f64 = rng.sample(Open01);
-
- x = x_.ln() / ziggurat_tables::ZIG_NORM_R;
- y = y_.ln();
- }
-
- if u < 0.0 {
- x - ziggurat_tables::ZIG_NORM_R
- } else {
- ziggurat_tables::ZIG_NORM_R - x
- }
- }
-
- ziggurat(
- rng,
- true, // this is symmetric
- &ziggurat_tables::ZIG_NORM_X,
- &ziggurat_tables::ZIG_NORM_F,
- pdf,
- zero_case,
- )
- }
-}
-
-/// The normal distribution `N(mean, std_dev**2)`.
-///
-/// This uses the ZIGNOR variant of the Ziggurat method, see [`StandardNormal`]
-/// for more details.
-///
-/// Note that [`StandardNormal`] is an optimised implementation for mean 0, and
-/// standard deviation 1.
-///
-/// [`StandardNormal`]: crate::distributions::StandardNormal
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Normal {
- mean: f64,
- std_dev: f64,
-}
-
-impl Normal {
- /// Construct a new `Normal` distribution with the given mean and
- /// standard deviation.
- ///
- /// # Panics
- ///
- /// Panics if `std_dev < 0`.
- #[inline]
- pub fn new(mean: f64, std_dev: f64) -> Normal {
- assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
- Normal { mean, std_dev }
- }
-}
-impl Distribution<f64> for Normal {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- let n = rng.sample(StandardNormal);
- self.mean + self.std_dev * n
- }
-}
-
-
-/// The log-normal distribution `ln N(mean, std_dev**2)`.
-///
-/// If `X` is log-normal distributed, then `ln(X)` is `N(mean, std_dev**2)`
-/// distributed.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct LogNormal {
- norm: Normal,
-}
-
-impl LogNormal {
- /// Construct a new `LogNormal` distribution with the given mean
- /// and standard deviation.
- ///
- /// # Panics
- ///
- /// Panics if `std_dev < 0`.
- #[inline]
- pub fn new(mean: f64, std_dev: f64) -> LogNormal {
- assert!(std_dev >= 0.0, "LogNormal::new called with `std_dev` < 0");
- LogNormal {
- norm: Normal::new(mean, std_dev),
- }
- }
-}
-impl Distribution<f64> for LogNormal {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- self.norm.sample(rng).exp()
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::{LogNormal, Normal};
- use crate::distributions::Distribution;
-
- #[test]
- fn test_normal() {
- let norm = Normal::new(10.0, 10.0);
- let mut rng = crate::test::rng(210);
- for _ in 0..1000 {
- norm.sample(&mut rng);
- }
- }
- #[test]
- #[should_panic]
- fn test_normal_invalid_sd() {
- Normal::new(10.0, -1.0);
- }
-
-
- #[test]
- fn test_log_normal() {
- let lnorm = LogNormal::new(10.0, 10.0);
- let mut rng = crate::test::rng(211);
- for _ in 0..1000 {
- lnorm.sample(&mut rng);
- }
- }
- #[test]
- #[should_panic]
- fn test_log_normal_invalid_sd() {
- LogNormal::new(10.0, -1.0);
- }
-}
diff --git a/src/distributions/other.rs b/src/distributions/other.rs
index c95060e..f62fe59 100644
--- a/src/distributions/other.rs
+++ b/src/distributions/other.rs
@@ -14,9 +14,12 @@
use crate::distributions::{Distribution, Standard, Uniform};
use crate::Rng;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
// ----- Sampling distributions -----
-/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
+/// Sample a `u8`, uniformly distributed over ASCII letters and numbers:
/// a-z, A-Z and 0-9.
///
/// # Example
@@ -29,11 +32,30 @@
/// let mut rng = thread_rng();
/// let chars: String = iter::repeat(())
/// .map(|()| rng.sample(Alphanumeric))
+/// .map(char::from)
/// .take(7)
/// .collect();
/// println!("Random chars: {}", chars);
/// ```
+///
+/// # Passwords
+///
+/// Users sometimes ask whether it is safe to use a string of random characters
+/// as a password. In principle, all RNGs in Rand implementing `CryptoRng` are
+/// suitable as a source of randomness for generating passwords (if they are
+/// properly seeded), but it is more conservative to only use randomness
+/// directly from the operating system via the `getrandom` crate, or the
+/// corresponding bindings of a crypto library.
+///
+/// When generating passwords or keys, it is important to consider the threat
+/// model and in some cases the memorability of the password. This is out of
+/// scope of the Rand project, and therefore we defer to the following
+/// references:
+///
+/// - [Wikipedia article on Password Strength](https://en.wikipedia.org/wiki/Password_strength)
+/// - [Diceware for generating memorable passwords](https://en.wikipedia.org/wiki/Diceware)
#[derive(Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Alphanumeric;
@@ -60,8 +82,8 @@
}
}
-impl Distribution<char> for Alphanumeric {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
+impl Distribution<u8> for Alphanumeric {
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u8 {
const RANGE: u32 = 26 + 26 + 10;
const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
@@ -73,7 +95,7 @@
loop {
let var = rng.next_u32() >> (32 - 6);
if var < RANGE {
- return GEN_ASCII_STR_CHARSET[var as usize] as char;
+ return GEN_ASCII_STR_CHARSET[var as usize];
}
}
}
@@ -184,7 +206,7 @@
mod tests {
use super::*;
use crate::RngCore;
- #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::string::String;
+ #[cfg(feature = "alloc")] use alloc::string::String;
#[test]
fn test_misc() {
@@ -217,7 +239,7 @@
// take the rejection sampling path.
let mut incorrect = false;
for _ in 0..100 {
- let c = rng.sample(Alphanumeric);
+ let c: char = rng.sample(Alphanumeric).into();
incorrect |= !((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') );
@@ -245,7 +267,7 @@
'\u{ed692}',
'\u{35888}',
]);
- test_samples(&Alphanumeric, 'a', &['h', 'm', 'e', '3', 'M']);
+ test_samples(&Alphanumeric, 0, &[104, 109, 101, 51, 77]);
test_samples(&Standard, false, &[true, true, false, true, false]);
test_samples(&Standard, None as Option<bool>, &[
Some(true),
diff --git a/src/distributions/pareto.rs b/src/distributions/pareto.rs
deleted file mode 100644
index ac5473b..0000000
--- a/src/distributions/pareto.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Pareto distribution.
-#![allow(deprecated)]
-
-use crate::distributions::{Distribution, OpenClosed01};
-use crate::Rng;
-
-/// Samples floating-point numbers according to the Pareto distribution
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Pareto {
- scale: f64,
- inv_neg_shape: f64,
-}
-
-impl Pareto {
- /// Construct a new Pareto distribution with given `scale` and `shape`.
- ///
- /// In the literature, `scale` is commonly written as x<sub>m</sub> or k and
- /// `shape` is often written as α.
- ///
- /// # Panics
- ///
- /// `scale` and `shape` have to be non-zero and positive.
- pub fn new(scale: f64, shape: f64) -> Pareto {
- assert!((scale > 0.) & (shape > 0.));
- Pareto {
- scale,
- inv_neg_shape: -1.0 / shape,
- }
- }
-}
-
-impl Distribution<f64> for Pareto {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- let u: f64 = rng.sample(OpenClosed01);
- self.scale * u.powf(self.inv_neg_shape)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::Pareto;
- use crate::distributions::Distribution;
-
- #[test]
- #[should_panic]
- fn invalid() {
- Pareto::new(0., 0.);
- }
-
- #[test]
- fn sample() {
- let scale = 1.0;
- let shape = 2.0;
- let d = Pareto::new(scale, shape);
- let mut rng = crate::test::rng(1);
- for _ in 0..1000 {
- let r = d.sample(&mut rng);
- assert!(r >= scale);
- }
- }
-}
diff --git a/src/distributions/poisson.rs b/src/distributions/poisson.rs
deleted file mode 100644
index ce94d75..0000000
--- a/src/distributions/poisson.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2016-2017 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Poisson distribution.
-#![allow(deprecated)]
-
-use crate::distributions::utils::log_gamma;
-use crate::distributions::{Cauchy, Distribution};
-use crate::Rng;
-
-/// The Poisson distribution `Poisson(lambda)`.
-///
-/// This distribution has a density function:
-/// `f(k) = lambda^k * exp(-lambda) / k!` for `k >= 0`.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Poisson {
- lambda: f64,
- // precalculated values
- exp_lambda: f64,
- log_lambda: f64,
- sqrt_2lambda: f64,
- magic_val: f64,
-}
-
-impl Poisson {
- /// Construct a new `Poisson` with the given shape parameter
- /// `lambda`. Panics if `lambda <= 0`.
- pub fn new(lambda: f64) -> Poisson {
- assert!(lambda > 0.0, "Poisson::new called with lambda <= 0");
- let log_lambda = lambda.ln();
- Poisson {
- lambda,
- exp_lambda: (-lambda).exp(),
- log_lambda,
- sqrt_2lambda: (2.0 * lambda).sqrt(),
- magic_val: lambda * log_lambda - log_gamma(1.0 + lambda),
- }
- }
-}
-
-impl Distribution<u64> for Poisson {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
- // using the algorithm from Numerical Recipes in C
-
- // for low expected values use the Knuth method
- if self.lambda < 12.0 {
- let mut result = 0;
- let mut p = 1.0;
- while p > self.exp_lambda {
- p *= rng.gen::<f64>();
- result += 1;
- }
- result - 1
- }
- // high expected values - rejection method
- else {
- let mut int_result: u64;
-
- // we use the Cauchy distribution as the comparison distribution
- // f(x) ~ 1/(1+x^2)
- let cauchy = Cauchy::new(0.0, 1.0);
-
- loop {
- let mut result;
- let mut comp_dev;
-
- loop {
- // draw from the Cauchy distribution
- comp_dev = rng.sample(cauchy);
- // shift the peak of the comparison ditribution
- result = self.sqrt_2lambda * comp_dev + self.lambda;
- // repeat the drawing until we are in the range of possible values
- if result >= 0.0 {
- break;
- }
- }
- // now the result is a random variable greater than 0 with Cauchy distribution
- // the result should be an integer value
- result = result.floor();
- int_result = result as u64;
-
- // this is the ratio of the Poisson distribution to the comparison distribution
- // the magic value scales the distribution function to a range of approximately 0-1
- // since it is not exact, we multiply the ratio by 0.9 to avoid ratios greater than 1
- // this doesn't change the resulting distribution, only increases the rate of failed drawings
- let check = 0.9
- * (1.0 + comp_dev * comp_dev)
- * (result * self.log_lambda - log_gamma(1.0 + result) - self.magic_val).exp();
-
- // check with uniform random value - if below the threshold, we are within the target distribution
- if rng.gen::<f64>() <= check {
- break;
- }
- }
- int_result
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::Poisson;
- use crate::distributions::Distribution;
-
- #[test]
- #[cfg_attr(miri, ignore)] // Miri is too slow
- fn test_poisson_10() {
- let poisson = Poisson::new(10.0);
- let mut rng = crate::test::rng(123);
- let mut sum = 0;
- for _ in 0..1000 {
- sum += poisson.sample(&mut rng);
- }
- let avg = (sum as f64) / 1000.0;
- println!("Poisson average: {}", avg);
- assert!((avg - 10.0).abs() < 0.5); // not 100% certain, but probable enough
- }
-
- #[test]
- fn test_poisson_15() {
- // Take the 'high expected values' path
- let poisson = Poisson::new(15.0);
- let mut rng = crate::test::rng(123);
- let mut sum = 0;
- for _ in 0..1000 {
- sum += poisson.sample(&mut rng);
- }
- let avg = (sum as f64) / 1000.0;
- println!("Poisson average: {}", avg);
- assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
- }
-
- #[test]
- #[should_panic]
- fn test_poisson_invalid_lambda_zero() {
- Poisson::new(0.0);
- }
-
- #[test]
- #[should_panic]
- fn test_poisson_invalid_lambda_neg() {
- Poisson::new(-10.0);
- }
-}
diff --git a/src/distributions/triangular.rs b/src/distributions/triangular.rs
deleted file mode 100644
index 37be198..0000000
--- a/src/distributions/triangular.rs
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The triangular distribution.
-#![allow(deprecated)]
-
-use crate::distributions::{Distribution, Standard};
-use crate::Rng;
-
-/// The triangular distribution.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Triangular {
- min: f64,
- max: f64,
- mode: f64,
-}
-
-impl Triangular {
- /// Construct a new `Triangular` with minimum `min`, maximum `max` and mode
- /// `mode`.
- ///
- /// # Panics
- ///
- /// If `max < mode`, `mode < max` or `max == min`.
- #[inline]
- pub fn new(min: f64, max: f64, mode: f64) -> Triangular {
- assert!(max >= mode);
- assert!(mode >= min);
- assert!(max != min);
- Triangular { min, max, mode }
- }
-}
-
-impl Distribution<f64> for Triangular {
- #[inline]
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- let f: f64 = rng.sample(Standard);
- let diff_mode_min = self.mode - self.min;
- let diff_max_min = self.max - self.min;
- if f * diff_max_min < diff_mode_min {
- self.min + (f * diff_max_min * diff_mode_min).sqrt()
- } else {
- self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt()
- }
- }
-}
-
-#[cfg(test)]
-mod test {
- use super::Triangular;
- use crate::distributions::Distribution;
-
- #[test]
- fn test_new() {
- for &(min, max, mode) in &[
- (-1., 1., 0.),
- (1., 2., 1.),
- (5., 25., 25.),
- (1e-5, 1e5, 1e-3),
- (0., 1., 0.9),
- (-4., -0.5, -2.),
- (-13.039, 8.41, 1.17),
- ] {
- println!("{} {} {}", min, max, mode);
- let _ = Triangular::new(min, max, mode);
- }
- }
-
- #[test]
- fn test_sample() {
- let norm = Triangular::new(0., 1., 0.5);
- let mut rng = crate::test::rng(1);
- for _ in 0..1000 {
- norm.sample(&mut rng);
- }
- }
-}
diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs
index 8584152..bbd9694 100644
--- a/src/distributions/uniform.rs
+++ b/src/distributions/uniform.rs
@@ -1,4 +1,4 @@
-// Copyright 2018 Developers of the Rand project.
+// Copyright 2018-2020 Developers of the Rand project.
// Copyright 2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
@@ -34,7 +34,7 @@
//! let side = Uniform::new(-10.0, 10.0);
//!
//! // sample between 1 and 10 points
-//! for _ in 0..rng.gen_range(1, 11) {
+//! for _ in 0..rng.gen_range(1..=10) {
//! // sample a point from the square with sides -10 - 10 in two dimensions
//! let (x, y) = (rng.sample(side), rng.sample(side));
//! println!("Point: {}, {}", x, y);
@@ -105,24 +105,28 @@
#[cfg(not(feature = "std"))] use core::time::Duration;
#[cfg(feature = "std")] use std::time::Duration;
+use core::ops::{Range, RangeInclusive};
use crate::distributions::float::IntoFloat;
use crate::distributions::utils::{BoolAsSIMD, FloatAsSIMD, FloatSIMDUtils, WideningMultiply};
use crate::distributions::Distribution;
-use crate::Rng;
+use crate::{Rng, RngCore};
#[cfg(not(feature = "std"))]
#[allow(unused_imports)] // rustc doesn't detect that this is actually used
use crate::distributions::utils::Float;
-
#[cfg(feature = "simd_support")] use packed_simd::*;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// Sample values uniformly between two bounds.
///
/// [`Uniform::new`] and [`Uniform::new_inclusive`] construct a uniform
/// distribution sampling from the given range; these functions may do extra
-/// work up front to make sampling of multiple values faster.
+/// work up front to make sampling of multiple values faster. If only one sample
+/// from the range is required, [`Rng::gen_range`] can be more efficient.
///
/// When sampling from a constant range, many calculations can happen at
/// compile-time and all methods should be fast; for floating-point ranges and
@@ -137,7 +141,7 @@
/// are of lower quality than the high bits.
///
/// Implementations must sample in `[low, high)` range for
-/// `Uniform::new(low, high)`, i.e., excluding `high`. In particular care must
+/// `Uniform::new(low, high)`, i.e., excluding `high`. In particular, care must
/// be taken to ensure that rounding never results values `< low` or `>= high`.
///
/// # Example
@@ -145,20 +149,29 @@
/// ```
/// use rand::distributions::{Distribution, Uniform};
///
-/// fn main() {
-/// let between = Uniform::from(10..10000);
-/// let mut rng = rand::thread_rng();
-/// let mut sum = 0;
-/// for _ in 0..1000 {
-/// sum += between.sample(&mut rng);
-/// }
-/// println!("{}", sum);
+/// let between = Uniform::from(10..10000);
+/// let mut rng = rand::thread_rng();
+/// let mut sum = 0;
+/// for _ in 0..1000 {
+/// sum += between.sample(&mut rng);
/// }
+/// println!("{}", sum);
+/// ```
+///
+/// For a single sample, [`Rng::gen_range`] may be prefered:
+///
+/// ```
+/// use rand::Rng;
+///
+/// let mut rng = rand::thread_rng();
+/// println!("{}", rng.gen_range(0..10));
/// ```
///
/// [`new`]: Uniform::new
/// [`new_inclusive`]: Uniform::new_inclusive
+/// [`Rng::gen_range`]: Rng::gen_range
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Uniform<X: SampleUniform>(X::Sampler);
impl<X: SampleUniform> Uniform<X> {
@@ -265,20 +278,38 @@
let uniform: Self = UniformSampler::new(low, high);
uniform.sample(rng)
}
+
+ /// Sample a single value uniformly from a range with inclusive lower bound
+ /// and inclusive upper bound `[low, high]`.
+ ///
+ /// By default this is implemented using
+ /// `UniformSampler::new_inclusive(low, high).sample(rng)`. However, for
+ /// some types more optimal implementations for single usage may be provided
+ /// via this method.
+ /// Results may not be identical.
+ fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(low: B1, high: B2, rng: &mut R)
+ -> Self::X
+ where B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized
+ {
+ let uniform: Self = UniformSampler::new_inclusive(low, high);
+ uniform.sample(rng)
+ }
}
-impl<X: SampleUniform> From<::core::ops::Range<X>> for Uniform<X> {
+impl<X: SampleUniform> From<Range<X>> for Uniform<X> {
fn from(r: ::core::ops::Range<X>) -> Uniform<X> {
Uniform::new(r.start, r.end)
}
}
-impl<X: SampleUniform> From<::core::ops::RangeInclusive<X>> for Uniform<X> {
+impl<X: SampleUniform> From<RangeInclusive<X>> for Uniform<X> {
fn from(r: ::core::ops::RangeInclusive<X>) -> Uniform<X> {
Uniform::new_inclusive(r.start(), r.end())
}
}
+
/// Helper trait similar to [`Borrow`] but implemented
/// only for SampleUniform and references to SampleUniform in
/// order to resolve ambiguity issues.
@@ -307,6 +338,43 @@
}
}
+/// Range that supports generating a single sample efficiently.
+///
+/// Any type implementing this trait can be used to specify the sampled range
+/// for `Rng::gen_range`.
+pub trait SampleRange<T> {
+ /// Generate a sample from the given range.
+ fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T;
+
+ /// Check whether the range is empty.
+ fn is_empty(&self) -> bool;
+}
+
+impl<T: SampleUniform + PartialOrd> SampleRange<T> for Range<T> {
+ #[inline]
+ fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T {
+ T::Sampler::sample_single(self.start, self.end, rng)
+ }
+
+ #[inline]
+ fn is_empty(&self) -> bool {
+ !(self.start < self.end)
+ }
+}
+
+impl<T: SampleUniform + PartialOrd> SampleRange<T> for RangeInclusive<T> {
+ #[inline]
+ fn sample_single<R: RngCore + ?Sized>(self, rng: &mut R) -> T {
+ T::Sampler::sample_single_inclusive(self.start(), self.end(), rng)
+ }
+
+ #[inline]
+ fn is_empty(&self) -> bool {
+ !(self.start() <= self.end())
+ }
+}
+
+
////////////////////////////////////////////////////////////////////////////////
// What follows are all back-ends.
@@ -347,6 +415,7 @@
/// multiply by `range`, the result is in the high word. Then comparing the low
/// word against `zone` makes sure our distribution is uniform.
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformInt<X> {
low: X,
range: X,
@@ -404,13 +473,14 @@
};
UniformInt {
- low: low,
+ low,
// These are really $unsigned values, but store as $ty:
range: range as $ty,
z: ints_to_reject as $unsigned as $ty,
}
}
+ #[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
let range = self.range as $unsigned as $u_large;
if range > 0 {
@@ -429,6 +499,7 @@
}
}
+ #[inline]
fn sample_single<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Self::X
where
B1: SampleBorrow<Self::X> + Sized,
@@ -437,7 +508,19 @@
let low = *low_b.borrow();
let high = *high_b.borrow();
assert!(low < high, "UniformSampler::sample_single: low >= high");
- let range = high.wrapping_sub(low) as $unsigned as $u_large;
+ Self::sample_single_inclusive(low, high - 1, rng)
+ }
+
+ #[inline]
+ fn sample_single_inclusive<R: Rng + ?Sized, B1, B2>(low_b: B1, high_b: B2, rng: &mut R) -> Self::X
+ where
+ B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized,
+ {
+ let low = *low_b.borrow();
+ let high = *high_b.borrow();
+ assert!(low <= high, "UniformSampler::sample_single_inclusive: low > high");
+ let range = high.wrapping_sub(low).wrapping_add(1) as $unsigned as $u_large;
let zone = if ::core::$unsigned::MAX <= ::core::u16::MAX as $unsigned {
// Using a modulus is faster than the approximation for
// i8 and i16. I suppose we trade the cost of one
@@ -478,7 +561,7 @@
#[cfg(not(target_os = "emscripten"))]
uniform_int_impl! { u128, u128, u128 }
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
macro_rules! uniform_simd_int_impl {
($ty:ident, $unsigned:ident, $u_scalar:ident) => {
// The "pick the largest zone that can fit in an `u32`" optimization
@@ -535,7 +618,7 @@
let zone = unsigned_max - ints_to_reject;
UniformInt {
- low: low,
+ low,
// These are really $unsigned values, but store as $ty:
range: range.cast(),
z: zone.cast(),
@@ -585,7 +668,7 @@
};
}
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
uniform_simd_int_impl! {
(u64x2, i64x2),
(u64x4, i64x4),
@@ -593,7 +676,7 @@
u64
}
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
uniform_simd_int_impl! {
(u32x2, i32x2),
(u32x4, i32x4),
@@ -602,7 +685,7 @@
u32
}
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
uniform_simd_int_impl! {
(u16x2, i16x2),
(u16x4, i16x4),
@@ -612,7 +695,7 @@
u16
}
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
uniform_simd_int_impl! {
(u8x2, i8x2),
(u8x4, i8x4),
@@ -623,6 +706,78 @@
u8
}
+impl SampleUniform for char {
+ type Sampler = UniformChar;
+}
+
+/// The back-end implementing [`UniformSampler`] for `char`.
+///
+/// Unless you are implementing [`UniformSampler`] for your own type, this type
+/// should not be used directly, use [`Uniform`] instead.
+///
+/// This differs from integer range sampling since the range `0xD800..=0xDFFF`
+/// are used for surrogate pairs in UCS and UTF-16, and consequently are not
+/// valid Unicode code points. We must therefore avoid sampling values in this
+/// range.
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+pub struct UniformChar {
+ sampler: UniformInt<u32>,
+}
+
+/// UTF-16 surrogate range start
+const CHAR_SURROGATE_START: u32 = 0xD800;
+/// UTF-16 surrogate range size
+const CHAR_SURROGATE_LEN: u32 = 0xE000 - CHAR_SURROGATE_START;
+
+/// Convert `char` to compressed `u32`
+fn char_to_comp_u32(c: char) -> u32 {
+ match c as u32 {
+ c if c >= CHAR_SURROGATE_START => c - CHAR_SURROGATE_LEN,
+ c => c,
+ }
+}
+
+impl UniformSampler for UniformChar {
+ type X = char;
+
+ #[inline] // if the range is constant, this helps LLVM to do the
+ // calculations at compile-time.
+ fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where
+ B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized,
+ {
+ let low = char_to_comp_u32(*low_b.borrow());
+ let high = char_to_comp_u32(*high_b.borrow());
+ let sampler = UniformInt::<u32>::new(low, high);
+ UniformChar { sampler }
+ }
+
+ #[inline] // if the range is constant, this helps LLVM to do the
+ // calculations at compile-time.
+ fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
+ where
+ B1: SampleBorrow<Self::X> + Sized,
+ B2: SampleBorrow<Self::X> + Sized,
+ {
+ let low = char_to_comp_u32(*low_b.borrow());
+ let high = char_to_comp_u32(*high_b.borrow());
+ let sampler = UniformInt::<u32>::new_inclusive(low, high);
+ UniformChar { sampler }
+ }
+
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
+ let mut x = self.sampler.sample(rng);
+ if x >= CHAR_SURROGATE_START {
+ x += CHAR_SURROGATE_LEN;
+ }
+ // SAFETY: x must not be in surrogate range or greater than char::MAX.
+ // This relies on range constructors which accept char arguments.
+ // Validity of input char values is assumed.
+ unsafe { core::char::from_u32_unchecked(x) }
+ }
+}
/// The back-end implementing [`UniformSampler`] for floating-point types.
///
@@ -644,6 +799,7 @@
/// [`new_inclusive`]: UniformSampler::new_inclusive
/// [`Standard`]: crate::distributions::Standard
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformFloat<X> {
low: X,
scale: X,
@@ -837,12 +993,14 @@
/// Unless you are implementing [`UniformSampler`] for your own types, this type
/// should not be used directly, use [`Uniform`] instead.
#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UniformDuration {
mode: UniformDurationMode,
offset: u32,
}
#[derive(Debug, Copy, Clone)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
enum UniformDurationMode {
Small {
secs: u64,
@@ -947,7 +1105,7 @@
max_nanos,
secs,
} => {
- // constant folding means this is at least as fast as `gen_range`
+ // constant folding means this is at least as fast as `Rng::sample(Range)`
let nano_range = Uniform::new(0, 1_000_000_000);
loop {
let s = secs.sample(rng);
@@ -967,6 +1125,56 @@
use super::*;
use crate::rngs::mock::StepRng;
+ #[test]
+ #[cfg(feature = "serde1")]
+ fn test_serialization_uniform_duration() {
+ let distr = UniformDuration::new(std::time::Duration::from_secs(10), std::time::Duration::from_secs(60));
+ let de_distr: UniformDuration = bincode::deserialize(&bincode::serialize(&distr).unwrap()).unwrap();
+ assert_eq!(
+ distr.offset, de_distr.offset
+ );
+ match (distr.mode, de_distr.mode) {
+ (UniformDurationMode::Small {secs: a_secs, nanos: a_nanos}, UniformDurationMode::Small {secs, nanos}) => {
+ assert_eq!(a_secs, secs);
+
+ assert_eq!(a_nanos.0.low, nanos.0.low);
+ assert_eq!(a_nanos.0.range, nanos.0.range);
+ assert_eq!(a_nanos.0.z, nanos.0.z);
+ }
+ (UniformDurationMode::Medium {nanos: a_nanos} , UniformDurationMode::Medium {nanos}) => {
+ assert_eq!(a_nanos.0.low, nanos.0.low);
+ assert_eq!(a_nanos.0.range, nanos.0.range);
+ assert_eq!(a_nanos.0.z, nanos.0.z);
+ }
+ (UniformDurationMode::Large {max_secs:a_max_secs, max_nanos:a_max_nanos, secs:a_secs}, UniformDurationMode::Large {max_secs, max_nanos, secs} ) => {
+ assert_eq!(a_max_secs, max_secs);
+ assert_eq!(a_max_nanos, max_nanos);
+
+ assert_eq!(a_secs.0.low, secs.0.low);
+ assert_eq!(a_secs.0.range, secs.0.range);
+ assert_eq!(a_secs.0.z, secs.0.z);
+ }
+ _ => panic!("`UniformDurationMode` was not serialized/deserialized correctly")
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "serde1")]
+ fn test_uniform_serialization() {
+ let unit_box: Uniform<i32> = Uniform::new(-1, 1);
+ let de_unit_box: Uniform<i32> = bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
+
+ assert_eq!(unit_box.0.low, de_unit_box.0.low);
+ assert_eq!(unit_box.0.range, de_unit_box.0.range);
+ assert_eq!(unit_box.0.z, de_unit_box.0.z);
+
+ let unit_box: Uniform<f32> = Uniform::new(-1., 1.);
+ let de_unit_box: Uniform<f32> = bincode::deserialize(&bincode::serialize(&unit_box).unwrap()).unwrap();
+
+ assert_eq!(unit_box.0.low, de_unit_box.0.low);
+ assert_eq!(unit_box.0.scale, de_unit_box.0.scale);
+ }
+
#[should_panic]
#[test]
fn test_uniform_bad_limits_equal_int() {
@@ -1024,7 +1232,7 @@
}
for _ in 0..1000 {
- let v: $ty = rng.gen_range(low, high);
+ let v = <$ty as SampleUniform>::Sampler::sample_single(low, high, &mut rng);
assert!($le(low, v) && $lt(v, high));
}
}
@@ -1058,7 +1266,7 @@
#[cfg(not(target_os = "emscripten"))]
t!(i128, u128);
- #[cfg(all(feature = "simd_support", feature = "nightly"))]
+ #[cfg(feature = "simd_support")]
{
t!(u8x2, u8x4, u8x8, u8x16, u8x32, u8x64 => u8);
t!(i8x2, i8x4, i8x8, i8x16, i8x32, i8x64 => i8);
@@ -1073,6 +1281,27 @@
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
+ fn test_char() {
+ let mut rng = crate::test::rng(891);
+ let mut max = core::char::from_u32(0).unwrap();
+ for _ in 0..100 {
+ let c = rng.gen_range('A'..='Z');
+ assert!('A' <= c && c <= 'Z');
+ max = max.max(c);
+ }
+ assert_eq!(max, 'Z');
+ let d = Uniform::new(
+ core::char::from_u32(0xD7F0).unwrap(),
+ core::char::from_u32(0xE010).unwrap(),
+ );
+ for _ in 0..100 {
+ let c = d.sample(&mut rng);
+ assert!((c as u32) < 0xD800 || (c as u32) > 0xDFFF);
+ }
+ }
+
+ #[test]
+ #[cfg_attr(miri, ignore)] // Miri is too slow
fn test_floats() {
let mut rng = crate::test::rng(252);
let mut zero_rng = StepRng::new(0, 0);
@@ -1106,7 +1335,8 @@
assert!(low_scalar <= v && v < high_scalar);
let v = rng.sample(my_incl_uniform).extract(lane);
assert!(low_scalar <= v && v <= high_scalar);
- let v = rng.gen_range(low, high).extract(lane);
+ let v = <$ty as SampleUniform>::Sampler
+ ::sample_single(low, high, &mut rng).extract(lane);
assert!(low_scalar <= v && v < high_scalar);
}
@@ -1117,7 +1347,9 @@
assert_eq!(zero_rng.sample(my_uniform).extract(lane), low_scalar);
assert_eq!(zero_rng.sample(my_incl_uniform).extract(lane), low_scalar);
- assert_eq!(zero_rng.gen_range(low, high).extract(lane), low_scalar);
+ assert_eq!(<$ty as SampleUniform>::Sampler
+ ::sample_single(low, high, &mut zero_rng)
+ .extract(lane), low_scalar);
assert!(max_rng.sample(my_uniform).extract(lane) < high_scalar);
assert!(max_rng.sample(my_incl_uniform).extract(lane) <= high_scalar);
@@ -1130,7 +1362,9 @@
(-1i64 << $bits_shifted) as u64,
);
assert!(
- lowering_max_rng.gen_range(low, high).extract(lane) < high_scalar
+ <$ty as SampleUniform>::Sampler
+ ::sample_single(low, high, &mut lowering_max_rng)
+ .extract(lane) < high_scalar
);
}
}
@@ -1178,7 +1412,7 @@
use std::panic::catch_unwind;
fn range<T: SampleUniform>(low: T, high: T) {
let mut rng = crate::test::rng(253);
- rng.gen_range(low, high);
+ T::Sampler::sample_single(low, high, &mut rng);
}
macro_rules! t {
diff --git a/src/distributions/unit_circle.rs b/src/distributions/unit_circle.rs
deleted file mode 100644
index 37885d8..0000000
--- a/src/distributions/unit_circle.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::{Distribution, Uniform};
-use crate::Rng;
-
-/// Samples uniformly from the edge of the unit circle in two dimensions.
-///
-/// Implemented via a method by von Neumann[^1].
-///
-/// [^1]: von Neumann, J. (1951) [*Various Techniques Used in Connection with
-/// Random Digits.*](https://mcnp.lanl.gov/pdf_files/nbs_vonneumann.pdf)
-/// NBS Appl. Math. Ser., No. 12. Washington, DC: U.S. Government Printing
-/// Office, pp. 36-38.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct UnitCircle;
-
-impl UnitCircle {
- /// Construct a new `UnitCircle` distribution.
- #[inline]
- pub fn new() -> UnitCircle {
- UnitCircle
- }
-}
-
-impl Distribution<[f64; 2]> for UnitCircle {
- #[inline]
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 2] {
- let uniform = Uniform::new(-1., 1.);
- let mut x1;
- let mut x2;
- let mut sum;
- loop {
- x1 = uniform.sample(rng);
- x2 = uniform.sample(rng);
- sum = x1 * x1 + x2 * x2;
- if sum < 1. {
- break;
- }
- }
- let diff = x1 * x1 - x2 * x2;
- [diff / sum, 2. * x1 * x2 / sum]
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::UnitCircle;
- use crate::distributions::Distribution;
-
- /// Assert that two numbers are almost equal to each other.
- ///
- /// On panic, this macro will print the values of the expressions with their
- /// debug representations.
- macro_rules! assert_almost_eq {
- ($a:expr, $b:expr, $prec:expr) => {
- let diff = ($a - $b).abs();
- if diff > $prec {
- panic!(format!(
- "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \
- (left: `{}`, right: `{}`)",
- diff, $prec, $a, $b
- ));
- }
- };
- }
-
- #[test]
- fn norm() {
- let mut rng = crate::test::rng(1);
- let dist = UnitCircle::new();
- for _ in 0..1000 {
- let x = dist.sample(&mut rng);
- assert_almost_eq!(x[0] * x[0] + x[1] * x[1], 1., 1e-15);
- }
- }
-
- #[test]
- fn value_stability() {
- let mut rng = crate::test::rng(2);
- let expected = [
- [-0.9965658683520504, -0.08280380447614634],
- [-0.9790853270389644, -0.20345004884984505],
- [-0.8449189758898707, 0.5348943112253227],
- ];
- let samples = [
- UnitCircle.sample(&mut rng),
- UnitCircle.sample(&mut rng),
- UnitCircle.sample(&mut rng),
- ];
- assert_eq!(samples, expected);
- }
-}
diff --git a/src/distributions/unit_sphere.rs b/src/distributions/unit_sphere.rs
deleted file mode 100644
index 5b8c8ad..0000000
--- a/src/distributions/unit_sphere.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(deprecated)]
-#![allow(clippy::all)]
-
-use crate::distributions::{Distribution, Uniform};
-use crate::Rng;
-
-/// Samples uniformly from the surface of the unit sphere in three dimensions.
-///
-/// Implemented via a method by Marsaglia[^1].
-///
-/// [^1]: Marsaglia, George (1972). [*Choosing a Point from the Surface of a
-/// Sphere.*](https://doi.org/10.1214/aoms/1177692644)
-/// Ann. Math. Statist. 43, no. 2, 645--646.
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct UnitSphereSurface;
-
-impl UnitSphereSurface {
- /// Construct a new `UnitSphereSurface` distribution.
- #[inline]
- pub fn new() -> UnitSphereSurface {
- UnitSphereSurface
- }
-}
-
-impl Distribution<[f64; 3]> for UnitSphereSurface {
- #[inline]
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> [f64; 3] {
- let uniform = Uniform::new(-1., 1.);
- loop {
- let (x1, x2) = (uniform.sample(rng), uniform.sample(rng));
- let sum = x1 * x1 + x2 * x2;
- if sum >= 1. {
- continue;
- }
- let factor = 2. * (1.0_f64 - sum).sqrt();
- return [x1 * factor, x2 * factor, 1. - 2. * sum];
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::UnitSphereSurface;
- use crate::distributions::Distribution;
-
- /// Assert that two numbers are almost equal to each other.
- ///
- /// On panic, this macro will print the values of the expressions with their
- /// debug representations.
- macro_rules! assert_almost_eq {
- ($a:expr, $b:expr, $prec:expr) => {
- let diff = ($a - $b).abs();
- if diff > $prec {
- panic!(format!(
- "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \
- (left: `{}`, right: `{}`)",
- diff, $prec, $a, $b
- ));
- }
- };
- }
-
- #[test]
- fn norm() {
- let mut rng = crate::test::rng(1);
- let dist = UnitSphereSurface::new();
- for _ in 0..1000 {
- let x = dist.sample(&mut rng);
- assert_almost_eq!(x[0] * x[0] + x[1] * x[1] + x[2] * x[2], 1., 1e-15);
- }
- }
-
- #[test]
- fn value_stability() {
- let mut rng = crate::test::rng(2);
- let expected = [
- [0.03247542860231647, -0.7830477442152738, 0.6211131755296027],
- [-0.09978440840914075, 0.9706650829833128, -0.21875184231323952],
- [0.2735582468624679, 0.9435374242279655, -0.1868234852870203],
- ];
- let samples = [
- UnitSphereSurface.sample(&mut rng),
- UnitSphereSurface.sample(&mut rng),
- UnitSphereSurface.sample(&mut rng),
- ];
- assert_eq!(samples, expected);
- }
-}
diff --git a/src/distributions/utils.rs b/src/distributions/utils.rs
index 2d36b02..e3bceb8 100644
--- a/src/distributions/utils.rs
+++ b/src/distributions/utils.rs
@@ -8,12 +8,10 @@
//! Math helper functions
-#[cfg(feature = "std")] use crate::distributions::ziggurat_tables;
-#[cfg(feature = "std")] use crate::Rng;
#[cfg(feature = "simd_support")] use packed_simd::*;
-pub trait WideningMultiply<RHS = Self> {
+pub(crate) trait WideningMultiply<RHS = Self> {
type Output;
fn wmul(self, x: RHS) -> Self::Output;
@@ -145,7 +143,7 @@
#[cfg(target_pointer_width = "64")]
wmul_impl_usize! { u64 }
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
+#[cfg(feature = "simd_support")]
mod simd_wmul {
use super::*;
#[cfg(target_arch = "x86")] use core::arch::x86::*;
@@ -161,9 +159,8 @@
}
wmul_impl! { (u16x2, u32x2),, 16 }
- #[cfg(not(target_feature = "sse2"))]
wmul_impl! { (u16x4, u32x4),, 16 }
- #[cfg(not(target_feature = "sse4.2"))]
+ #[cfg(not(target_feature = "sse2"))]
wmul_impl! { (u16x8, u32x8),, 16 }
#[cfg(not(target_feature = "avx2"))]
wmul_impl! { (u16x16, u32x16),, 16 }
@@ -189,8 +186,6 @@
}
#[cfg(target_feature = "sse2")]
- wmul_impl_16! { u16x4, __m64, _mm_mulhi_pu16, _mm_mullo_pi16 }
- #[cfg(target_feature = "sse4.2")]
wmul_impl_16! { u16x8, __m128i, _mm_mulhi_epu16, _mm_mullo_epi16 }
#[cfg(target_feature = "avx2")]
wmul_impl_16! { u16x16, __m256i, _mm256_mulhi_epu16, _mm256_mullo_epi16 }
@@ -210,9 +205,6 @@
wmul_impl_large! { (u32x16,) u32, 16 }
wmul_impl_large! { (u64x2, u64x4, u64x8,) u64, 32 }
}
-#[cfg(all(feature = "simd_support", feature = "nightly"))]
-pub use self::simd_wmul::*;
-
/// Helper trait when dealing with scalar and SIMD floating point types.
pub(crate) trait FloatSIMDUtils {
@@ -435,113 +427,3 @@
#[cfg(feature="simd_support")] simd_impl! { f64x2, f64, m64x2, u64x2 }
#[cfg(feature="simd_support")] simd_impl! { f64x4, f64, m64x4, u64x4 }
#[cfg(feature="simd_support")] simd_impl! { f64x8, f64, m64x8, u64x8 }
-
-/// Calculates ln(gamma(x)) (natural logarithm of the gamma
-/// function) using the Lanczos approximation.
-///
-/// The approximation expresses the gamma function as:
-/// `gamma(z+1) = sqrt(2*pi)*(z+g+0.5)^(z+0.5)*exp(-z-g-0.5)*Ag(z)`
-/// `g` is an arbitrary constant; we use the approximation with `g=5`.
-///
-/// Noting that `gamma(z+1) = z*gamma(z)` and applying `ln` to both sides:
-/// `ln(gamma(z)) = (z+0.5)*ln(z+g+0.5)-(z+g+0.5) + ln(sqrt(2*pi)*Ag(z)/z)`
-///
-/// `Ag(z)` is an infinite series with coefficients that can be calculated
-/// ahead of time - we use just the first 6 terms, which is good enough
-/// for most purposes.
-#[cfg(feature = "std")]
-pub fn log_gamma(x: f64) -> f64 {
- // precalculated 6 coefficients for the first 6 terms of the series
- let coefficients: [f64; 6] = [
- 76.18009172947146,
- -86.50532032941677,
- 24.01409824083091,
- -1.231739572450155,
- 0.1208650973866179e-2,
- -0.5395239384953e-5,
- ];
-
- // (x+0.5)*ln(x+g+0.5)-(x+g+0.5)
- let tmp = x + 5.5;
- let log = (x + 0.5) * tmp.ln() - tmp;
-
- // the first few terms of the series for Ag(x)
- let mut a = 1.000000000190015;
- let mut denom = x;
- for coeff in &coefficients {
- denom += 1.0;
- a += coeff / denom;
- }
-
- // get everything together
- // a is Ag(x)
- // 2.5066... is sqrt(2pi)
- log + (2.5066282746310005 * a / x).ln()
-}
-
-/// Sample a random number using the Ziggurat method (specifically the
-/// ZIGNOR variant from Doornik 2005). Most of the arguments are
-/// directly from the paper:
-///
-/// * `rng`: source of randomness
-/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
-/// * `X`: the $x_i$ abscissae.
-/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
-/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
-/// * `pdf`: the probability density function
-/// * `zero_case`: manual sampling from the tail when we chose the
-/// bottom box (i.e. i == 0)
-
-// the perf improvement (25-50%) is definitely worth the extra code
-// size from force-inlining.
-#[cfg(feature = "std")]
-#[inline(always)]
-pub fn ziggurat<R: Rng + ?Sized, P, Z>(
- rng: &mut R,
- symmetric: bool,
- x_tab: ziggurat_tables::ZigTable,
- f_tab: ziggurat_tables::ZigTable,
- mut pdf: P,
- mut zero_case: Z
-) -> f64
-where
- P: FnMut(f64) -> f64,
- Z: FnMut(&mut R, f64) -> f64,
-{
- use crate::distributions::float::IntoFloat;
- loop {
- // As an optimisation we re-implement the conversion to a f64.
- // From the remaining 12 most significant bits we use 8 to construct `i`.
- // This saves us generating a whole extra random number, while the added
- // precision of using 64 bits for f64 does not buy us much.
- let bits = rng.next_u64();
- let i = bits as usize & 0xff;
-
- let u = if symmetric {
- // Convert to a value in the range [2,4) and substract to get [-1,1)
- // We can't convert to an open range directly, that would require
- // substracting `3.0 - EPSILON`, which is not representable.
- // It is possible with an extra step, but an open range does not
- // seem neccesary for the ziggurat algorithm anyway.
- (bits >> 12).into_float_with_exponent(1) - 3.0
- } else {
- // Convert to a value in the range [1,2) and substract to get (0,1)
- (bits >> 12).into_float_with_exponent(0) - (1.0 - ::core::f64::EPSILON / 2.0)
- };
- let x = u * x_tab[i];
-
- let test_x = if symmetric { x.abs() } else { x };
-
- // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
- if test_x < x_tab[i + 1] {
- return x;
- }
- if i == 0 {
- return zero_case(rng, u);
- }
- // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
- if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
- return x;
- }
- }
-}
diff --git a/src/distributions/weibull.rs b/src/distributions/weibull.rs
deleted file mode 100644
index ffbc93b..0000000
--- a/src/distributions/weibull.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! The Weibull distribution.
-#![allow(deprecated)]
-
-use crate::distributions::{Distribution, OpenClosed01};
-use crate::Rng;
-
-/// Samples floating-point numbers according to the Weibull distribution
-#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
-#[derive(Clone, Copy, Debug)]
-pub struct Weibull {
- inv_shape: f64,
- scale: f64,
-}
-
-impl Weibull {
- /// Construct a new `Weibull` distribution with given `scale` and `shape`.
- ///
- /// # Panics
- ///
- /// `scale` and `shape` have to be non-zero and positive.
- pub fn new(scale: f64, shape: f64) -> Weibull {
- assert!((scale > 0.) & (shape > 0.));
- Weibull {
- inv_shape: 1. / shape,
- scale,
- }
- }
-}
-
-impl Distribution<f64> for Weibull {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
- let x: f64 = rng.sample(OpenClosed01);
- self.scale * (-x.ln()).powf(self.inv_shape)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::Weibull;
- use crate::distributions::Distribution;
-
- #[test]
- #[should_panic]
- fn invalid() {
- Weibull::new(0., 0.);
- }
-
- #[test]
- fn sample() {
- let scale = 1.0;
- let shape = 2.0;
- let d = Weibull::new(scale, shape);
- let mut rng = crate::test::rng(1);
- for _ in 0..1000 {
- let r = d.sample(&mut rng);
- assert!(r >= 0.);
- }
- }
-}
diff --git a/src/distributions/weighted.rs b/src/distributions/weighted.rs
new file mode 100644
index 0000000..6dd9273
--- /dev/null
+++ b/src/distributions/weighted.rs
@@ -0,0 +1,48 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Weighted index sampling
+//!
+//! This module is deprecated. Use [`crate::distributions::WeightedIndex`] and
+//! [`crate::distributions::WeightedError`] instead.
+
+pub use super::{WeightedIndex, WeightedError};
+
+#[allow(missing_docs)]
+#[deprecated(since = "0.8.0", note = "moved to rand_distr crate")]
+pub mod alias_method {
+ // This module exists to provide a deprecation warning which minimises
+ // compile errors, but still fails to compile if ever used.
+ use core::marker::PhantomData;
+ use alloc::vec::Vec;
+ use super::WeightedError;
+
+ #[derive(Debug)]
+ pub struct WeightedIndex<W: Weight> {
+ _phantom: PhantomData<W>,
+ }
+ impl<W: Weight> WeightedIndex<W> {
+ pub fn new(_weights: Vec<W>) -> Result<Self, WeightedError> {
+ Err(WeightedError::NoItem)
+ }
+ }
+
+ pub trait Weight {}
+ macro_rules! impl_weight {
+ () => {};
+ ($T:ident, $($more:ident,)*) => {
+ impl Weight for $T {}
+ impl_weight!($($more,)*);
+ };
+ }
+ impl_weight!(f64, f32,);
+ impl_weight!(u8, u16, u32, u64, usize,);
+ impl_weight!(i8, i16, i32, i64, isize,);
+ #[cfg(not(target_os = "emscripten"))]
+ impl_weight!(u128, i128,);
+}
diff --git a/src/distributions/weighted/alias_method.rs b/src/distributions/weighted/alias_method.rs
deleted file mode 100644
index 7d42a35..0000000
--- a/src/distributions/weighted/alias_method.rs
+++ /dev/null
@@ -1,517 +0,0 @@
-//! This module contains an implementation of alias method for sampling random
-//! indices with probabilities proportional to a collection of weights.
-
-use super::WeightedError;
-#[cfg(not(feature = "std"))] use crate::alloc::vec;
-#[cfg(not(feature = "std"))] use crate::alloc::vec::Vec;
-use crate::distributions::uniform::SampleUniform;
-use crate::distributions::Distribution;
-use crate::distributions::Uniform;
-use crate::Rng;
-use core::fmt;
-use core::iter::Sum;
-use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
-
-/// A distribution using weighted sampling to pick a discretely selected item.
-///
-/// Sampling a [`WeightedIndex<W>`] distribution returns the index of a randomly
-/// selected element from the vector used to create the [`WeightedIndex<W>`].
-/// The chance of a given element being picked is proportional to the value of
-/// the element. The weights can have any type `W` for which a implementation of
-/// [`Weight`] exists.
-///
-/// # Performance
-///
-/// Given that `n` is the number of items in the vector used to create an
-/// [`WeightedIndex<W>`], [`WeightedIndex<W>`] will require `O(n)` amount of
-/// memory. More specifically it takes up some constant amount of memory plus
-/// the vector used to create it and a [`Vec<u32>`] with capacity `n`.
-///
-/// Time complexity for the creation of a [`WeightedIndex<W>`] is `O(n)`.
-/// Sampling is `O(1)`, it makes a call to [`Uniform<u32>::sample`] and a call
-/// to [`Uniform<W>::sample`].
-///
-/// # Example
-///
-/// ```
-/// use rand::distributions::weighted::alias_method::WeightedIndex;
-/// use rand::prelude::*;
-///
-/// let choices = vec!['a', 'b', 'c'];
-/// let weights = vec![2, 1, 1];
-/// let dist = WeightedIndex::new(weights).unwrap();
-/// let mut rng = thread_rng();
-/// for _ in 0..100 {
-/// // 50% chance to print 'a', 25% chance to print 'b', 25% chance to print 'c'
-/// println!("{}", choices[dist.sample(&mut rng)]);
-/// }
-///
-/// let items = [('a', 0), ('b', 3), ('c', 7)];
-/// let dist2 = WeightedIndex::new(items.iter().map(|item| item.1).collect()).unwrap();
-/// for _ in 0..100 {
-/// // 0% chance to print 'a', 30% chance to print 'b', 70% chance to print 'c'
-/// println!("{}", items[dist2.sample(&mut rng)].0);
-/// }
-/// ```
-///
-/// [`WeightedIndex<W>`]: crate::distributions::weighted::alias_method::WeightedIndex
-/// [`Weight`]: crate::distributions::weighted::alias_method::Weight
-/// [`Vec<u32>`]: Vec
-/// [`Uniform<u32>::sample`]: Distribution::sample
-/// [`Uniform<W>::sample`]: Distribution::sample
-pub struct WeightedIndex<W: Weight> {
- aliases: Vec<u32>,
- no_alias_odds: Vec<W>,
- uniform_index: Uniform<u32>,
- uniform_within_weight_sum: Uniform<W>,
-}
-
-impl<W: Weight> WeightedIndex<W> {
- /// Creates a new [`WeightedIndex`].
- ///
- /// Returns an error if:
- /// - The vector is empty.
- /// - The vector is longer than `u32::MAX`.
- /// - For any weight `w`: `w < 0` or `w > max` where `max = W::MAX /
- /// weights.len()`.
- /// - The sum of weights is zero.
- pub fn new(weights: Vec<W>) -> Result<Self, WeightedError> {
- let n = weights.len();
- if n == 0 {
- return Err(WeightedError::NoItem);
- } else if n > ::core::u32::MAX as usize {
- return Err(WeightedError::TooMany);
- }
- let n = n as u32;
-
- let max_weight_size = W::try_from_u32_lossy(n)
- .map(|n| W::MAX / n)
- .unwrap_or(W::ZERO);
- if !weights
- .iter()
- .all(|&w| W::ZERO <= w && w <= max_weight_size)
- {
- return Err(WeightedError::InvalidWeight);
- }
-
- // The sum of weights will represent 100% of no alias odds.
- let weight_sum = Weight::sum(weights.as_slice());
- // Prevent floating point overflow due to rounding errors.
- let weight_sum = if weight_sum > W::MAX {
- W::MAX
- } else {
- weight_sum
- };
- if weight_sum == W::ZERO {
- return Err(WeightedError::AllWeightsZero);
- }
-
- // `weight_sum` would have been zero if `try_from_lossy` causes an error here.
- let n_converted = W::try_from_u32_lossy(n).unwrap();
-
- let mut no_alias_odds = weights;
- for odds in no_alias_odds.iter_mut() {
- *odds *= n_converted;
- // Prevent floating point overflow due to rounding errors.
- *odds = if *odds > W::MAX { W::MAX } else { *odds };
- }
-
- /// This struct is designed to contain three data structures at once,
- /// sharing the same memory. More precisely it contains two linked lists
- /// and an alias map, which will be the output of this method. To keep
- /// the three data structures from getting in each other's way, it must
- /// be ensured that a single index is only ever in one of them at the
- /// same time.
- struct Aliases {
- aliases: Vec<u32>,
- smalls_head: u32,
- bigs_head: u32,
- }
-
- impl Aliases {
- fn new(size: u32) -> Self {
- Aliases {
- aliases: vec![0; size as usize],
- smalls_head: ::core::u32::MAX,
- bigs_head: ::core::u32::MAX,
- }
- }
-
- fn push_small(&mut self, idx: u32) {
- self.aliases[idx as usize] = self.smalls_head;
- self.smalls_head = idx;
- }
-
- fn push_big(&mut self, idx: u32) {
- self.aliases[idx as usize] = self.bigs_head;
- self.bigs_head = idx;
- }
-
- fn pop_small(&mut self) -> u32 {
- let popped = self.smalls_head;
- self.smalls_head = self.aliases[popped as usize];
- popped
- }
-
- fn pop_big(&mut self) -> u32 {
- let popped = self.bigs_head;
- self.bigs_head = self.aliases[popped as usize];
- popped
- }
-
- fn smalls_is_empty(&self) -> bool {
- self.smalls_head == ::core::u32::MAX
- }
-
- fn bigs_is_empty(&self) -> bool {
- self.bigs_head == ::core::u32::MAX
- }
-
- fn set_alias(&mut self, idx: u32, alias: u32) {
- self.aliases[idx as usize] = alias;
- }
- }
-
- let mut aliases = Aliases::new(n);
-
- // Split indices into those with small weights and those with big weights.
- for (index, &odds) in no_alias_odds.iter().enumerate() {
- if odds < weight_sum {
- aliases.push_small(index as u32);
- } else {
- aliases.push_big(index as u32);
- }
- }
-
- // Build the alias map by finding an alias with big weight for each index with
- // small weight.
- while !aliases.smalls_is_empty() && !aliases.bigs_is_empty() {
- let s = aliases.pop_small();
- let b = aliases.pop_big();
-
- aliases.set_alias(s, b);
- no_alias_odds[b as usize] =
- no_alias_odds[b as usize] - weight_sum + no_alias_odds[s as usize];
-
- if no_alias_odds[b as usize] < weight_sum {
- aliases.push_small(b);
- } else {
- aliases.push_big(b);
- }
- }
-
- // The remaining indices should have no alias odds of about 100%. This is due to
- // numeric accuracy. Otherwise they would be exactly 100%.
- while !aliases.smalls_is_empty() {
- no_alias_odds[aliases.pop_small() as usize] = weight_sum;
- }
- while !aliases.bigs_is_empty() {
- no_alias_odds[aliases.pop_big() as usize] = weight_sum;
- }
-
- // Prepare distributions for sampling. Creating them beforehand improves
- // sampling performance.
- let uniform_index = Uniform::new(0, n);
- let uniform_within_weight_sum = Uniform::new(W::ZERO, weight_sum);
-
- Ok(Self {
- aliases: aliases.aliases,
- no_alias_odds,
- uniform_index,
- uniform_within_weight_sum,
- })
- }
-}
-
-impl<W: Weight> Distribution<usize> for WeightedIndex<W> {
- fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
- let candidate = rng.sample(self.uniform_index);
- if rng.sample(&self.uniform_within_weight_sum) < self.no_alias_odds[candidate as usize] {
- candidate as usize
- } else {
- self.aliases[candidate as usize] as usize
- }
- }
-}
-
-impl<W: Weight> fmt::Debug for WeightedIndex<W>
-where
- W: fmt::Debug,
- Uniform<W>: fmt::Debug,
-{
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_struct("WeightedIndex")
- .field("aliases", &self.aliases)
- .field("no_alias_odds", &self.no_alias_odds)
- .field("uniform_index", &self.uniform_index)
- .field("uniform_within_weight_sum", &self.uniform_within_weight_sum)
- .finish()
- }
-}
-
-impl<W: Weight> Clone for WeightedIndex<W>
-where Uniform<W>: Clone
-{
- fn clone(&self) -> Self {
- Self {
- aliases: self.aliases.clone(),
- no_alias_odds: self.no_alias_odds.clone(),
- uniform_index: self.uniform_index.clone(),
- uniform_within_weight_sum: self.uniform_within_weight_sum.clone(),
- }
- }
-}
-
-/// Trait that must be implemented for weights, that are used with
-/// [`WeightedIndex`]. Currently no guarantees on the correctness of
-/// [`WeightedIndex`] are given for custom implementations of this trait.
-pub trait Weight:
- Sized
- + Copy
- + SampleUniform
- + PartialOrd
- + Add<Output = Self>
- + AddAssign
- + Sub<Output = Self>
- + SubAssign
- + Mul<Output = Self>
- + MulAssign
- + Div<Output = Self>
- + DivAssign
- + Sum
-{
- /// Maximum number representable by `Self`.
- const MAX: Self;
-
- /// Element of `Self` equivalent to 0.
- const ZERO: Self;
-
- /// Produce an instance of `Self` from a `u32` value, or return `None` if
- /// out of range. Loss of precision (where `Self` is a floating point type)
- /// is acceptable.
- fn try_from_u32_lossy(n: u32) -> Option<Self>;
-
- /// Sums all values in slice `values`.
- fn sum(values: &[Self]) -> Self {
- values.iter().map(|x| *x).sum()
- }
-}
-
-macro_rules! impl_weight_for_float {
- ($T: ident) => {
- impl Weight for $T {
- const MAX: Self = ::core::$T::MAX;
- const ZERO: Self = 0.0;
-
- fn try_from_u32_lossy(n: u32) -> Option<Self> {
- Some(n as $T)
- }
-
- fn sum(values: &[Self]) -> Self {
- pairwise_sum(values)
- }
- }
- };
-}
-
-/// In comparison to naive accumulation, the pairwise sum algorithm reduces
-/// rounding errors when there are many floating point values.
-fn pairwise_sum<T: Weight>(values: &[T]) -> T {
- if values.len() <= 32 {
- values.iter().map(|x| *x).sum()
- } else {
- let mid = values.len() / 2;
- let (a, b) = values.split_at(mid);
- pairwise_sum(a) + pairwise_sum(b)
- }
-}
-
-macro_rules! impl_weight_for_int {
- ($T: ident) => {
- impl Weight for $T {
- const MAX: Self = ::core::$T::MAX;
- const ZERO: Self = 0;
-
- fn try_from_u32_lossy(n: u32) -> Option<Self> {
- let n_converted = n as Self;
- if n_converted >= Self::ZERO && n_converted as u32 == n {
- Some(n_converted)
- } else {
- None
- }
- }
- }
- };
-}
-
-impl_weight_for_float!(f64);
-impl_weight_for_float!(f32);
-impl_weight_for_int!(usize);
-#[cfg(not(target_os = "emscripten"))]
-impl_weight_for_int!(u128);
-impl_weight_for_int!(u64);
-impl_weight_for_int!(u32);
-impl_weight_for_int!(u16);
-impl_weight_for_int!(u8);
-impl_weight_for_int!(isize);
-#[cfg(not(target_os = "emscripten"))]
-impl_weight_for_int!(i128);
-impl_weight_for_int!(i64);
-impl_weight_for_int!(i32);
-impl_weight_for_int!(i16);
-impl_weight_for_int!(i8);
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- #[cfg_attr(miri, ignore)] // Miri is too slow
- fn test_weighted_index_f32() {
- test_weighted_index(f32::into);
-
- // Floating point special cases
- assert_eq!(
- WeightedIndex::new(vec![::core::f32::INFINITY]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- assert_eq!(
- WeightedIndex::new(vec![-0_f32]).unwrap_err(),
- WeightedError::AllWeightsZero
- );
- assert_eq!(
- WeightedIndex::new(vec![-1_f32]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- assert_eq!(
- WeightedIndex::new(vec![-::core::f32::INFINITY]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- assert_eq!(
- WeightedIndex::new(vec![::core::f32::NAN]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- }
-
- #[cfg(not(target_os = "emscripten"))]
- #[test]
- #[cfg_attr(miri, ignore)] // Miri is too slow
- fn test_weighted_index_u128() {
- test_weighted_index(|x: u128| x as f64);
- }
-
- #[cfg(all(rustc_1_26, not(target_os = "emscripten")))]
- #[test]
- #[cfg_attr(miri, ignore)] // Miri is too slow
- fn test_weighted_index_i128() {
- test_weighted_index(|x: i128| x as f64);
-
- // Signed integer special cases
- assert_eq!(
- WeightedIndex::new(vec![-1_i128]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- assert_eq!(
- WeightedIndex::new(vec![::core::i128::MIN]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- }
-
- #[test]
- #[cfg_attr(miri, ignore)] // Miri is too slow
- fn test_weighted_index_u8() {
- test_weighted_index(u8::into);
- }
-
- #[test]
- #[cfg_attr(miri, ignore)] // Miri is too slow
- fn test_weighted_index_i8() {
- test_weighted_index(i8::into);
-
- // Signed integer special cases
- assert_eq!(
- WeightedIndex::new(vec![-1_i8]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- assert_eq!(
- WeightedIndex::new(vec![::core::i8::MIN]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- }
-
- fn test_weighted_index<W: Weight, F: Fn(W) -> f64>(w_to_f64: F)
- where WeightedIndex<W>: fmt::Debug {
- const NUM_WEIGHTS: u32 = 10;
- const ZERO_WEIGHT_INDEX: u32 = 3;
- const NUM_SAMPLES: u32 = 15000;
- let mut rng = crate::test::rng(0x9c9fa0b0580a7031);
-
- let weights = {
- let mut weights = Vec::with_capacity(NUM_WEIGHTS as usize);
- let random_weight_distribution = crate::distributions::Uniform::new_inclusive(
- W::ZERO,
- W::MAX / W::try_from_u32_lossy(NUM_WEIGHTS).unwrap(),
- );
- for _ in 0..NUM_WEIGHTS {
- weights.push(rng.sample(&random_weight_distribution));
- }
- weights[ZERO_WEIGHT_INDEX as usize] = W::ZERO;
- weights
- };
- let weight_sum = weights.iter().map(|w| *w).sum::<W>();
- let expected_counts = weights
- .iter()
- .map(|&w| w_to_f64(w) / w_to_f64(weight_sum) * NUM_SAMPLES as f64)
- .collect::<Vec<f64>>();
- let weight_distribution = WeightedIndex::new(weights).unwrap();
-
- let mut counts = vec![0; NUM_WEIGHTS as usize];
- for _ in 0..NUM_SAMPLES {
- counts[rng.sample(&weight_distribution)] += 1;
- }
-
- assert_eq!(counts[ZERO_WEIGHT_INDEX as usize], 0);
- for (count, expected_count) in counts.into_iter().zip(expected_counts) {
- let difference = (count as f64 - expected_count).abs();
- let max_allowed_difference = NUM_SAMPLES as f64 / NUM_WEIGHTS as f64 * 0.1;
- assert!(difference <= max_allowed_difference);
- }
-
- assert_eq!(
- WeightedIndex::<W>::new(vec![]).unwrap_err(),
- WeightedError::NoItem
- );
- assert_eq!(
- WeightedIndex::new(vec![W::ZERO]).unwrap_err(),
- WeightedError::AllWeightsZero
- );
- assert_eq!(
- WeightedIndex::new(vec![W::MAX, W::MAX]).unwrap_err(),
- WeightedError::InvalidWeight
- );
- }
-
- #[test]
- fn value_stability() {
- fn test_samples<W: Weight>(weights: Vec<W>, buf: &mut [usize], expected: &[usize]) {
- assert_eq!(buf.len(), expected.len());
- let distr = WeightedIndex::new(weights).unwrap();
- let mut rng = crate::test::rng(0x9c9fa0b0580a7031);
- for r in buf.iter_mut() {
- *r = rng.sample(&distr);
- }
- assert_eq!(buf, expected);
- }
-
- let mut buf = [0; 10];
- test_samples(vec![1i32, 1, 1, 1, 1, 1, 1, 1, 1], &mut buf, &[
- 6, 5, 7, 5, 8, 7, 6, 2, 3, 7,
- ]);
- test_samples(vec![0.7f32, 0.1, 0.1, 0.1], &mut buf, &[
- 2, 0, 0, 0, 0, 0, 0, 0, 1, 3,
- ]);
- test_samples(vec![1.0f64, 0.999, 0.998, 0.997], &mut buf, &[
- 2, 1, 2, 3, 2, 1, 3, 2, 1, 1,
- ]);
- }
-}
diff --git a/src/distributions/weighted/mod.rs b/src/distributions/weighted_index.rs
similarity index 84%
rename from src/distributions/weighted/mod.rs
rename to src/distributions/weighted_index.rs
index 357e3a9..07ba53e 100644
--- a/src/distributions/weighted/mod.rs
+++ b/src/distributions/weighted_index.rs
@@ -7,16 +7,6 @@
// except according to those terms.
//! Weighted index sampling
-//!
-//! This module provides two implementations for sampling indices:
-//!
-//! * [`WeightedIndex`] allows `O(log N)` sampling
-//! * [`alias_method::WeightedIndex`] allows `O(1)` sampling, but with
-//! much greater set-up cost
-//!
-//! [`alias_method::WeightedIndex`]: alias_method/struct.WeightedIndex.html
-
-pub mod alias_method;
use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
use crate::distributions::Distribution;
@@ -25,10 +15,12 @@
use core::fmt;
// Note that this whole module is only imported if feature="alloc" is enabled.
-#[cfg(not(feature = "std"))] use crate::alloc::vec::Vec;
+use alloc::vec::Vec;
-/// A distribution using weighted sampling to pick a discretely selected
-/// item.
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
+/// A distribution using weighted sampling of discrete items
///
/// Sampling a `WeightedIndex` distribution returns the index of a randomly
/// selected element from the iterator used when the `WeightedIndex` was
@@ -38,6 +30,11 @@
///
/// # Performance
///
+/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
+/// `N` is the number of weights. As an alternative,
+/// [`rand_distr::weighted_alias`](https://docs.rs/rand_distr/*/rand_distr/weighted_alias/index.html)
+/// supports `O(1)` sampling, but with much higher initialisation cost.
+///
/// A `WeightedIndex<X>` contains a `Vec<X>` and a [`Uniform<X>`] and so its
/// size is the sum of the size of those objects, possibly plus some alignment.
///
@@ -46,15 +43,12 @@
/// `Vec` doesn't guarantee a particular growth strategy, additional memory
/// might be allocated but not used. Since the `WeightedIndex` object also
/// contains, this might cause additional allocations, though for primitive
-/// types, ['Uniform<X>`] doesn't allocate any memory.
-///
-/// Time complexity of sampling from `WeightedIndex` is `O(log N)` where
-/// `N` is the number of weights.
+/// types, [`Uniform<X>`] doesn't allocate any memory.
///
/// Sampling from `WeightedIndex` will result in a single call to
/// `Uniform<X>::sample` (method of the [`Distribution`] trait), which typically
/// will request a single value from the underlying [`RngCore`], though the
-/// exact number depends on the implementaiton of `Uniform<X>::sample`.
+/// exact number depends on the implementation of `Uniform<X>::sample`.
///
/// # Example
///
@@ -79,9 +73,11 @@
/// }
/// ```
///
-/// [`Uniform<X>`]: crate::distributions::uniform::Uniform
+/// [`Uniform<X>`]: crate::distributions::Uniform
/// [`RngCore`]: crate::RngCore
#[derive(Debug, Clone)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub struct WeightedIndex<X: SampleUniform + PartialOrd> {
cumulative_weights: Vec<X>,
total_weight: X,
@@ -107,13 +103,15 @@
let mut total_weight: X = iter.next().ok_or(WeightedError::NoItem)?.borrow().clone();
let zero = <X as Default>::default();
- if total_weight < zero {
+ if !(total_weight >= zero) {
return Err(WeightedError::InvalidWeight);
}
let mut weights = Vec::<X>::with_capacity(iter.size_hint().0);
for w in iter {
- if *w.borrow() < zero {
+ // Note that `!(w >= x)` is not equivalent to `w < x` for partially
+ // ordered types due to NaNs which are equal to nothing.
+ if !(w.borrow() >= &zero) {
return Err(WeightedError::InvalidWeight);
}
weights.push(total_weight.clone());
@@ -163,10 +161,10 @@
return Err(WeightedError::InvalidWeight);
}
}
- if *w < zero {
+ if !(*w >= zero) {
return Err(WeightedError::InvalidWeight);
}
- if i >= self.cumulative_weights.len() + 1 {
+ if i > self.cumulative_weights.len() {
return Err(WeightedError::TooMany);
}
@@ -183,7 +181,7 @@
total_weight += w;
prev_i = Some(i);
}
- if total_weight == zero {
+ if total_weight <= zero {
return Err(WeightedError::AllWeightsZero);
}
@@ -245,6 +243,47 @@
mod test {
use super::*;
+ #[cfg(feature = "serde1")]
+ #[test]
+ fn test_weightedindex_serde1() {
+ let weighted_index = WeightedIndex::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).unwrap();
+
+ let ser_weighted_index = bincode::serialize(&weighted_index).unwrap();
+ let de_weighted_index: WeightedIndex<i32> =
+ bincode::deserialize(&ser_weighted_index).unwrap();
+
+ assert_eq!(
+ de_weighted_index.cumulative_weights,
+ weighted_index.cumulative_weights
+ );
+ assert_eq!(de_weighted_index.total_weight, weighted_index.total_weight);
+ }
+
+ #[test]
+ fn test_accepting_nan(){
+ assert_eq!(
+ WeightedIndex::new(&[core::f32::NAN, 0.5]).unwrap_err(),
+ WeightedError::InvalidWeight,
+ );
+ assert_eq!(
+ WeightedIndex::new(&[core::f32::NAN]).unwrap_err(),
+ WeightedError::InvalidWeight,
+ );
+ assert_eq!(
+ WeightedIndex::new(&[0.5, core::f32::NAN]).unwrap_err(),
+ WeightedError::InvalidWeight,
+ );
+
+ assert_eq!(
+ WeightedIndex::new(&[0.5, 7.0])
+ .unwrap()
+ .update_weights(&[(0, &core::f32::NAN)])
+ .unwrap_err(),
+ WeightedError::InvalidWeight,
+ )
+ }
+
+
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_weightedindex() {
@@ -382,13 +421,14 @@
}
/// Error type returned from `WeightedIndex::new`.
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WeightedError {
/// The provided weight collection contains no items.
NoItem,
- /// A weight is either less than zero, greater than the supported maximum or
- /// otherwise invalid.
+ /// A weight is either less than zero, greater than the supported maximum,
+ /// NaN, or otherwise invalid.
InvalidWeight,
/// All items in the provided weight collection are zero.
diff --git a/src/distributions/ziggurat_tables.rs b/src/distributions/ziggurat_tables.rs
deleted file mode 100644
index f830a60..0000000
--- a/src/distributions/ziggurat_tables.rs
+++ /dev/null
@@ -1,283 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-// Copyright 2013 The Rust Project Developers.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Tables for distributions which are sampled using the ziggurat
-// algorithm. Autogenerated by `ziggurat_tables.py`.
-
-pub type ZigTable = &'static [f64; 257];
-pub const ZIG_NORM_R: f64 = 3.654152885361008796;
-#[rustfmt::skip]
-pub static ZIG_NORM_X: [f64; 257] =
- [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
- 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
- 2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548,
- 2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056,
- 2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570,
- 2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761,
- 2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318,
- 2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520,
- 2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952,
- 2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565,
- 2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760,
- 2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995,
- 2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268,
- 2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957,
- 2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778,
- 2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715,
- 2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244,
- 1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896,
- 1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257,
- 1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081,
- 1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281,
- 1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566,
- 1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199,
- 1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933,
- 1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012,
- 1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086,
- 1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338,
- 1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526,
- 1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427,
- 1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339,
- 1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456,
- 1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553,
- 1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404,
- 1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369,
- 1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830,
- 1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425,
- 1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534,
- 1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964,
- 1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606,
- 1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679,
- 1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728,
- 1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732,
- 1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903,
- 1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552,
- 1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650,
- 1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240,
- 1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975,
- 1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151,
- 1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714,
- 1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538,
- 1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441,
- 1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750,
- 0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130,
- 0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997,
- 0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550,
- 0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752,
- 0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785,
- 0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653,
- 0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448,
- 0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928,
- 0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262,
- 0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393,
- 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746,
- 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806,
- 0.000000000000000000];
-#[rustfmt::skip]
-pub static ZIG_NORM_F: [f64; 257] =
- [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872,
- 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100,
- 0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839,
- 0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237,
- 0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690,
- 0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918,
- 0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664,
- 0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916,
- 0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854,
- 0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965,
- 0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509,
- 0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229,
- 0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627,
- 0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880,
- 0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014,
- 0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349,
- 0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352,
- 0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926,
- 0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563,
- 0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071,
- 0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654,
- 0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926,
- 0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112,
- 0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651,
- 0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589,
- 0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525,
- 0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988,
- 0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150,
- 0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837,
- 0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316,
- 0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984,
- 0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274,
- 0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396,
- 0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099,
- 0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340,
- 0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515,
- 0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344,
- 0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958,
- 0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668,
- 0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784,
- 0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519,
- 0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750,
- 0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481,
- 0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788,
- 0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658,
- 0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142,
- 0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700,
- 0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941,
- 0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916,
- 0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473,
- 0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719,
- 0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205,
- 0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991,
- 0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357,
- 0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376,
- 0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409,
- 0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437,
- 0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500,
- 0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902,
- 0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935,
- 0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077,
- 0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839,
- 0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247,
- 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
- 1.000000000000000000];
-pub const ZIG_EXP_R: f64 = 7.697117470131050077;
-#[rustfmt::skip]
-pub static ZIG_EXP_X: [f64; 257] =
- [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
- 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
- 5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530,
- 4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380,
- 4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857,
- 4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762,
- 3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744,
- 3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770,
- 3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608,
- 3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405,
- 3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160,
- 3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481,
- 3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601,
- 2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825,
- 2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780,
- 2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752,
- 2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489,
- 2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970,
- 2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815,
- 2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886,
- 2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372,
- 2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213,
- 2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027,
- 2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289,
- 2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526,
- 2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563,
- 1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943,
- 1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242,
- 1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954,
- 1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014,
- 1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566,
- 1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896,
- 1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334,
- 1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892,
- 1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092,
- 1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058,
- 1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504,
- 1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137,
- 1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189,
- 1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117,
- 1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330,
- 1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124,
- 1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677,
- 1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511,
- 1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813,
- 1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209,
- 1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735,
- 0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509,
- 0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311,
- 0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066,
- 0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206,
- 0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430,
- 0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102,
- 0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959,
- 0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947,
- 0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030,
- 0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626,
- 0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398,
- 0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235,
- 0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765,
- 0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122,
- 0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703,
- 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842,
- 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570,
- 0.000000000000000000];
-#[rustfmt::skip]
-pub static ZIG_EXP_F: [f64; 257] =
- [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573,
- 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797,
- 0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991,
- 0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981,
- 0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943,
- 0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355,
- 0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581,
- 0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221,
- 0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622,
- 0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431,
- 0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139,
- 0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289,
- 0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379,
- 0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030,
- 0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660,
- 0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816,
- 0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752,
- 0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435,
- 0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146,
- 0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197,
- 0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213,
- 0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145,
- 0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283,
- 0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641,
- 0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671,
- 0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602,
- 0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146,
- 0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839,
- 0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129,
- 0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081,
- 0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829,
- 0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083,
- 0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189,
- 0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654,
- 0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628,
- 0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956,
- 0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560,
- 0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543,
- 0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173,
- 0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967,
- 0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746,
- 0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252,
- 0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185,
- 0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223,
- 0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717,
- 0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449,
- 0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379,
- 0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056,
- 0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350,
- 0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209,
- 0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907,
- 0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836,
- 0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708,
- 0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881,
- 0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931,
- 0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056,
- 0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150,
- 0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560,
- 0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398,
- 0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177,
- 0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456,
- 0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838,
- 0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101,
- 0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477,
- 1.000000000000000000];
diff --git a/src/lib.rs b/src/lib.rs
index d42a79f..8bf7a9d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,7 +37,7 @@
//!
//! # The Book
//!
-//! For the user guide and futher documentation, please read
+//! For the user guide and further documentation, please read
//! [The Rust Rand Book](https://rust-random.github.io/book).
#![doc(
@@ -48,15 +48,17 @@
#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![doc(test(attr(allow(unused_variables), deny(warnings))))]
-#![cfg_attr(not(feature = "std"), no_std)]
-#![cfg_attr(all(feature = "simd_support", feature = "nightly"), feature(stdsimd))]
+#![no_std]
+#![cfg_attr(feature = "simd_support", feature(stdsimd))]
+#![cfg_attr(feature = "nightly", feature(slice_partition_at_index))]
+#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![allow(
- clippy::excessive_precision,
- clippy::unreadable_literal,
- clippy::float_cmp
+ clippy::float_cmp,
+ clippy::neg_cmp_op_on_partial_ord,
)]
-#[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc;
+#[cfg(feature = "std")] extern crate std;
+#[cfg(feature = "alloc")] extern crate alloc;
#[allow(unused)]
macro_rules! trace { ($($x:tt)*) => (
@@ -92,418 +94,20 @@
// Re-exports from rand_core
pub use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
-// Public exports
-#[cfg(feature = "std")] pub use crate::rngs::thread::thread_rng;
-
// Public modules
pub mod distributions;
pub mod prelude;
+mod rng;
pub mod rngs;
pub mod seq;
+// Public exports
+#[cfg(all(feature = "std", feature = "std_rng"))]
+pub use crate::rngs::thread::thread_rng;
+pub use rng::{Fill, Rng};
-use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
+#[cfg(all(feature = "std", feature = "std_rng"))]
use crate::distributions::{Distribution, Standard};
-use core::num::Wrapping;
-use core::{mem, slice};
-
-/// An automatically-implemented extension trait on [`RngCore`] providing high-level
-/// generic methods for sampling values and other convenience methods.
-///
-/// This is the primary trait to use when generating random values.
-///
-/// # Generic usage
-///
-/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some
-/// things are worth noting here:
-///
-/// - Since `Rng: RngCore` and every `RngCore` implements `Rng`, it makes no
-/// difference whether we use `R: Rng` or `R: RngCore`.
-/// - The `+ ?Sized` un-bounding allows functions to be called directly on
-/// type-erased references; i.e. `foo(r)` where `r: &mut RngCore`. Without
-/// this it would be necessary to write `foo(&mut r)`.
-///
-/// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some
-/// trade-offs. It allows the argument to be consumed directly without a `&mut`
-/// (which is how `from_rng(thread_rng())` works); also it still works directly
-/// on references (including type-erased references). Unfortunately within the
-/// function `foo` it is not known whether `rng` is a reference type or not,
-/// hence many uses of `rng` require an extra reference, either explicitly
-/// (`distr.sample(&mut rng)`) or implicitly (`rng.gen()`); one may hope the
-/// optimiser can remove redundant references later.
-///
-/// Example:
-///
-/// ```
-/// # use rand::thread_rng;
-/// use rand::Rng;
-///
-/// fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 {
-/// rng.gen()
-/// }
-///
-/// # let v = foo(&mut thread_rng());
-/// ```
-pub trait Rng: RngCore {
- /// Return a random value supporting the [`Standard`] distribution.
- ///
- /// # Example
- ///
- /// ```
- /// use rand::{thread_rng, Rng};
- ///
- /// let mut rng = thread_rng();
- /// let x: u32 = rng.gen();
- /// println!("{}", x);
- /// println!("{:?}", rng.gen::<(f64, bool)>());
- /// ```
- ///
- /// # Arrays and tuples
- ///
- /// The `rng.gen()` method is able to generate arrays (up to 32 elements)
- /// and tuples (up to 12 elements), so long as all element types can be
- /// generated.
- ///
- /// For arrays of integers, especially for those with small element types
- /// (< 64 bit), it will likely be faster to instead use [`Rng::fill`].
- ///
- /// ```
- /// use rand::{thread_rng, Rng};
- ///
- /// let mut rng = thread_rng();
- /// let tuple: (u8, i32, char) = rng.gen(); // arbitrary tuple support
- ///
- /// let arr1: [f32; 32] = rng.gen(); // array construction
- /// let mut arr2 = [0u8; 128];
- /// rng.fill(&mut arr2); // array fill
- /// ```
- ///
- /// [`Standard`]: distributions::Standard
- #[inline]
- fn gen<T>(&mut self) -> T
- where Standard: Distribution<T> {
- Standard.sample(self)
- }
-
- /// Generate a random value in the range [`low`, `high`), i.e. inclusive of
- /// `low` and exclusive of `high`.
- ///
- /// This function is optimised for the case that only a single sample is
- /// made from the given range. See also the [`Uniform`] distribution
- /// type which may be faster if sampling from the same range repeatedly.
- ///
- /// # Panics
- ///
- /// Panics if `low >= high`.
- ///
- /// # Example
- ///
- /// ```
- /// use rand::{thread_rng, Rng};
- ///
- /// let mut rng = thread_rng();
- /// let n: u32 = rng.gen_range(0, 10);
- /// println!("{}", n);
- /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64);
- /// println!("{}", m);
- /// ```
- ///
- /// [`Uniform`]: distributions::uniform::Uniform
- fn gen_range<T: SampleUniform, B1, B2>(&mut self, low: B1, high: B2) -> T
- where
- B1: SampleBorrow<T> + Sized,
- B2: SampleBorrow<T> + Sized,
- {
- T::Sampler::sample_single(low, high, self)
- }
-
- /// Sample a new value, using the given distribution.
- ///
- /// ### Example
- ///
- /// ```
- /// use rand::{thread_rng, Rng};
- /// use rand::distributions::Uniform;
- ///
- /// let mut rng = thread_rng();
- /// let x = rng.sample(Uniform::new(10u32, 15));
- /// // Type annotation requires two types, the type and distribution; the
- /// // distribution can be inferred.
- /// let y = rng.sample::<u16, _>(Uniform::new(10, 15));
- /// ```
- fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T {
- distr.sample(self)
- }
-
- /// Create an iterator that generates values using the given distribution.
- ///
- /// Note that this function takes its arguments by value. This works since
- /// `(&mut R): Rng where R: Rng` and
- /// `(&D): Distribution where D: Distribution`,
- /// however borrowing is not automatic hence `rng.sample_iter(...)` may
- /// need to be replaced with `(&mut rng).sample_iter(...)`.
- ///
- /// # Example
- ///
- /// ```
- /// use rand::{thread_rng, Rng};
- /// use rand::distributions::{Alphanumeric, Uniform, Standard};
- ///
- /// let rng = thread_rng();
- ///
- /// // Vec of 16 x f32:
- /// let v: Vec<f32> = rng.sample_iter(Standard).take(16).collect();
- ///
- /// // String:
- /// let s: String = rng.sample_iter(Alphanumeric).take(7).collect();
- ///
- /// // Combined values
- /// println!("{:?}", rng.sample_iter(Standard).take(5)
- /// .collect::<Vec<(f64, bool)>>());
- ///
- /// // Dice-rolling:
- /// let die_range = Uniform::new_inclusive(1, 6);
- /// let mut roll_die = rng.sample_iter(die_range);
- /// while roll_die.next().unwrap() != 6 {
- /// println!("Not a 6; rolling again!");
- /// }
- /// ```
- fn sample_iter<T, D>(self, distr: D) -> distributions::DistIter<D, Self, T>
- where
- D: Distribution<T>,
- Self: Sized,
- {
- distr.sample_iter(self)
- }
-
- /// Fill `dest` entirely with random bytes (uniform value distribution),
- /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices
- /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.).
- ///
- /// On big-endian platforms this performs byte-swapping to ensure
- /// portability of results from reproducible generators.
- ///
- /// This uses [`fill_bytes`] internally which may handle some RNG errors
- /// implicitly (e.g. waiting if the OS generator is not ready), but panics
- /// on other errors. See also [`try_fill`] which returns errors.
- ///
- /// # Example
- ///
- /// ```
- /// use rand::{thread_rng, Rng};
- ///
- /// let mut arr = [0i8; 20];
- /// thread_rng().fill(&mut arr[..]);
- /// ```
- ///
- /// [`fill_bytes`]: RngCore::fill_bytes
- /// [`try_fill`]: Rng::try_fill
- fn fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) {
- self.fill_bytes(dest.as_byte_slice_mut());
- dest.to_le();
- }
-
- /// Fill `dest` entirely with random bytes (uniform value distribution),
- /// where `dest` is any type supporting [`AsByteSliceMut`], namely slices
- /// and arrays over primitive integer types (`i8`, `i16`, `u32`, etc.).
- ///
- /// On big-endian platforms this performs byte-swapping to ensure
- /// portability of results from reproducible generators.
- ///
- /// This is identical to [`fill`] except that it uses [`try_fill_bytes`]
- /// internally and forwards RNG errors.
- ///
- /// # Example
- ///
- /// ```
- /// # use rand::Error;
- /// use rand::{thread_rng, Rng};
- ///
- /// # fn try_inner() -> Result<(), Error> {
- /// let mut arr = [0u64; 4];
- /// thread_rng().try_fill(&mut arr[..])?;
- /// # Ok(())
- /// # }
- ///
- /// # try_inner().unwrap()
- /// ```
- ///
- /// [`try_fill_bytes`]: RngCore::try_fill_bytes
- /// [`fill`]: Rng::fill
- fn try_fill<T: AsByteSliceMut + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> {
- self.try_fill_bytes(dest.as_byte_slice_mut())?;
- dest.to_le();
- Ok(())
- }
-
- /// Return a bool with a probability `p` of being true.
- ///
- /// See also the [`Bernoulli`] distribution, which may be faster if
- /// sampling from the same probability repeatedly.
- ///
- /// # Example
- ///
- /// ```
- /// use rand::{thread_rng, Rng};
- ///
- /// let mut rng = thread_rng();
- /// println!("{}", rng.gen_bool(1.0 / 3.0));
- /// ```
- ///
- /// # Panics
- ///
- /// If `p < 0` or `p > 1`.
- ///
- /// [`Bernoulli`]: distributions::bernoulli::Bernoulli
- #[inline]
- fn gen_bool(&mut self, p: f64) -> bool {
- let d = distributions::Bernoulli::new(p).unwrap();
- self.sample(d)
- }
-
- /// Return a bool with a probability of `numerator/denominator` of being
- /// true. I.e. `gen_ratio(2, 3)` has chance of 2 in 3, or about 67%, of
- /// returning true. If `numerator == denominator`, then the returned value
- /// is guaranteed to be `true`. If `numerator == 0`, then the returned
- /// value is guaranteed to be `false`.
- ///
- /// See also the [`Bernoulli`] distribution, which may be faster if
- /// sampling from the same `numerator` and `denominator` repeatedly.
- ///
- /// # Panics
- ///
- /// If `denominator == 0` or `numerator > denominator`.
- ///
- /// # Example
- ///
- /// ```
- /// use rand::{thread_rng, Rng};
- ///
- /// let mut rng = thread_rng();
- /// println!("{}", rng.gen_ratio(2, 3));
- /// ```
- ///
- /// [`Bernoulli`]: distributions::bernoulli::Bernoulli
- #[inline]
- fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool {
- let d = distributions::Bernoulli::from_ratio(numerator, denominator).unwrap();
- self.sample(d)
- }
-}
-
-impl<R: RngCore + ?Sized> Rng for R {}
-
-/// Trait for casting types to byte slices
-///
-/// This is used by the [`Rng::fill`] and [`Rng::try_fill`] methods.
-pub trait AsByteSliceMut {
- /// Return a mutable reference to self as a byte slice
- fn as_byte_slice_mut(&mut self) -> &mut [u8];
-
- /// Call `to_le` on each element (i.e. byte-swap on Big Endian platforms).
- fn to_le(&mut self);
-}
-
-impl AsByteSliceMut for [u8] {
- fn as_byte_slice_mut(&mut self) -> &mut [u8] {
- self
- }
-
- fn to_le(&mut self) {}
-}
-
-macro_rules! impl_as_byte_slice {
- () => {};
- ($t:ty) => {
- impl AsByteSliceMut for [$t] {
- fn as_byte_slice_mut(&mut self) -> &mut [u8] {
- if self.len() == 0 {
- unsafe {
- // must not use null pointer
- slice::from_raw_parts_mut(0x1 as *mut u8, 0)
- }
- } else {
- unsafe {
- slice::from_raw_parts_mut(self.as_mut_ptr()
- as *mut u8,
- self.len() * mem::size_of::<$t>()
- )
- }
- }
- }
-
- fn to_le(&mut self) {
- for x in self {
- *x = x.to_le();
- }
- }
- }
-
- impl AsByteSliceMut for [Wrapping<$t>] {
- fn as_byte_slice_mut(&mut self) -> &mut [u8] {
- if self.len() == 0 {
- unsafe {
- // must not use null pointer
- slice::from_raw_parts_mut(0x1 as *mut u8, 0)
- }
- } else {
- unsafe {
- slice::from_raw_parts_mut(self.as_mut_ptr()
- as *mut u8,
- self.len() * mem::size_of::<$t>()
- )
- }
- }
- }
-
- fn to_le(&mut self) {
- for x in self {
- *x = Wrapping(x.0.to_le());
- }
- }
- }
- };
- ($t:ty, $($tt:ty,)*) => {
- impl_as_byte_slice!($t);
- // TODO: this could replace above impl once Rust #32463 is fixed
- // impl_as_byte_slice!(Wrapping<$t>);
- impl_as_byte_slice!($($tt,)*);
- }
-}
-
-impl_as_byte_slice!(u16, u32, u64, usize,);
-#[cfg(not(target_os = "emscripten"))]
-impl_as_byte_slice!(u128);
-impl_as_byte_slice!(i8, i16, i32, i64, isize,);
-#[cfg(not(target_os = "emscripten"))]
-impl_as_byte_slice!(i128);
-
-macro_rules! impl_as_byte_slice_arrays {
- ($n:expr,) => {};
- ($n:expr, $N:ident) => {
- impl<T> AsByteSliceMut for [T; $n] where [T]: AsByteSliceMut {
- fn as_byte_slice_mut(&mut self) -> &mut [u8] {
- self[..].as_byte_slice_mut()
- }
-
- fn to_le(&mut self) {
- self[..].to_le()
- }
- }
- };
- ($n:expr, $N:ident, $($NN:ident,)*) => {
- impl_as_byte_slice_arrays!($n, $N);
- impl_as_byte_slice_arrays!($n - 1, $($NN,)*);
- };
- (!div $n:expr,) => {};
- (!div $n:expr, $N:ident, $($NN:ident,)*) => {
- impl_as_byte_slice_arrays!($n, $N);
- impl_as_byte_slice_arrays!(!div $n / 2, $($NN,)*);
- };
-}
-#[rustfmt::skip]
-impl_as_byte_slice_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,);
-impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,);
/// Generates a random value using the thread-local random number generator.
///
@@ -511,6 +115,33 @@
/// documentation of the entropy source and [`Standard`] for documentation of
/// distributions and type-specific generation.
///
+/// # Provided implementations
+///
+/// The following types have provided implementations that
+/// generate values with the following ranges and distributions:
+///
+/// * Integers (`i32`, `u32`, `isize`, `usize`, etc.): Uniformly distributed
+/// over all values of the type.
+/// * `char`: Uniformly distributed over all Unicode scalar values, i.e. all
+/// code points in the range `0...0x10_FFFF`, except for the range
+/// `0xD800...0xDFFF` (the surrogate code points). This includes
+/// unassigned/reserved code points.
+/// * `bool`: Generates `false` or `true`, each with probability 0.5.
+/// * Floating point types (`f32` and `f64`): Uniformly distributed in the
+/// half-open range `[0, 1)`. See notes below.
+/// * Wrapping integers (`Wrapping<T>`), besides the type identical to their
+/// normal integer variants.
+///
+/// Also supported is the generation of the following
+/// compound types where all component types are supported:
+///
+/// * Tuples (up to 12 elements): each element is generated sequentially.
+/// * Arrays (up to 32 elements): each element is generated sequentially;
+/// see also [`Rng::fill`] which supports arbitrary array length for integer
+/// types and tends to be faster for `u32` and smaller types.
+/// * `Option<T>` first generates a `bool`, and if true generates and returns
+/// `Some(value)` where `value: T`, otherwise returning `None`.
+///
/// # Examples
///
/// ```
@@ -547,7 +178,8 @@
/// ```
///
/// [`Standard`]: distributions::Standard
-#[cfg(feature = "std")]
+#[cfg(all(feature = "std", feature = "std_rng"))]
+#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
#[inline]
pub fn random<T>() -> T
where Standard: Distribution<T> {
@@ -557,8 +189,6 @@
#[cfg(test)]
mod test {
use super::*;
- use crate::rngs::mock::StepRng;
- #[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::boxed::Box;
/// Construct a deterministic RNG with the given seed
pub fn rng(seed: u64) -> impl RngCore {
@@ -569,126 +199,7 @@
}
#[test]
- fn test_fill_bytes_default() {
- let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0);
-
- // check every remainder mod 8, both in small and big vectors.
- let lengths = [0, 1, 2, 3, 4, 5, 6, 7, 80, 81, 82, 83, 84, 85, 86, 87];
- for &n in lengths.iter() {
- let mut buffer = [0u8; 87];
- let v = &mut buffer[0..n];
- r.fill_bytes(v);
-
- // use this to get nicer error messages.
- for (i, &byte) in v.iter().enumerate() {
- if byte == 0 {
- panic!("byte {} of {} is zero", i, n)
- }
- }
- }
- }
-
- #[test]
- fn test_fill() {
- let x = 9041086907909331047; // a random u64
- let mut rng = StepRng::new(x, 0);
-
- // Convert to byte sequence and back to u64; byte-swap twice if BE.
- let mut array = [0u64; 2];
- rng.fill(&mut array[..]);
- assert_eq!(array, [x, x]);
- assert_eq!(rng.next_u64(), x);
-
- // Convert to bytes then u32 in LE order
- let mut array = [0u32; 2];
- rng.fill(&mut array[..]);
- assert_eq!(array, [x as u32, (x >> 32) as u32]);
- assert_eq!(rng.next_u32(), x as u32);
-
- // Check equivalence using wrapped arrays
- let mut warray = [Wrapping(0u32); 2];
- rng.fill(&mut warray[..]);
- assert_eq!(array[0], warray[0].0);
- assert_eq!(array[1], warray[1].0);
- }
-
- #[test]
- fn test_fill_empty() {
- let mut array = [0u32; 0];
- let mut rng = StepRng::new(0, 1);
- rng.fill(&mut array);
- rng.fill(&mut array[..]);
- }
-
- #[test]
- fn test_gen_range() {
- let mut r = rng(101);
- for _ in 0..1000 {
- let a = r.gen_range(-4711, 17);
- assert!(a >= -4711 && a < 17);
- let a = r.gen_range(-3i8, 42);
- assert!(a >= -3i8 && a < 42i8);
- let a = r.gen_range(&10u16, 99);
- assert!(a >= 10u16 && a < 99u16);
- let a = r.gen_range(-100i32, &2000);
- assert!(a >= -100i32 && a < 2000i32);
- let a = r.gen_range(&12u32, &24u32);
- assert!(a >= 12u32 && a < 24u32);
-
- assert_eq!(r.gen_range(0u32, 1), 0u32);
- assert_eq!(r.gen_range(-12i64, -11), -12i64);
- assert_eq!(r.gen_range(3_000_000, 3_000_001), 3_000_000);
- }
- }
-
- #[test]
- #[should_panic]
- fn test_gen_range_panic_int() {
- let mut r = rng(102);
- r.gen_range(5, -2);
- }
-
- #[test]
- #[should_panic]
- fn test_gen_range_panic_usize() {
- let mut r = rng(103);
- r.gen_range(5, 2);
- }
-
- #[test]
- fn test_gen_bool() {
- let mut r = rng(105);
- for _ in 0..5 {
- assert_eq!(r.gen_bool(0.0), false);
- assert_eq!(r.gen_bool(1.0), true);
- }
- }
-
- #[test]
- fn test_rng_trait_object() {
- use crate::distributions::{Distribution, Standard};
- let mut rng = rng(109);
- let mut r = &mut rng as &mut dyn RngCore;
- r.next_u32();
- r.gen::<i32>();
- assert_eq!(r.gen_range(0, 1), 0);
- let _c: u8 = Standard.sample(&mut r);
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn test_rng_boxed_trait() {
- use crate::distributions::{Distribution, Standard};
- let rng = rng(110);
- let mut r = Box::new(rng) as Box<dyn RngCore>;
- r.next_u32();
- r.gen::<i32>();
- assert_eq!(r.gen_range(0, 1), 0);
- let _c: u8 = Standard.sample(&mut r);
- }
-
- #[test]
- #[cfg(feature = "std")]
+ #[cfg(all(feature = "std", feature = "std_rng"))]
fn test_random() {
// not sure how to test this aside from just getting some values
let _n: usize = random();
@@ -701,23 +212,4 @@
(f32, (f64, (f64,))),
) = random();
}
-
- #[test]
- #[cfg_attr(miri, ignore)] // Miri is too slow
- fn test_gen_ratio_average() {
- const NUM: u32 = 3;
- const DENOM: u32 = 10;
- const N: u32 = 100_000;
-
- let mut sum: u32 = 0;
- let mut rng = rng(111);
- for _ in 0..N {
- if rng.gen_ratio(NUM, DENOM) {
- sum += 1;
- }
- }
- // Have Binomial(N, NUM/DENOM) distribution
- let expected = (NUM * N) / DENOM; // exact integer
- assert!(((sum - expected) as i32).abs() < 500);
- }
}
diff --git a/src/prelude.rs b/src/prelude.rs
index 98ae3bb..51c457e 100644
--- a/src/prelude.rs
+++ b/src/prelude.rs
@@ -22,12 +22,13 @@
#[cfg(feature = "small_rng")]
#[doc(no_inline)]
pub use crate::rngs::SmallRng;
+#[cfg(feature = "std_rng")]
#[doc(no_inline)] pub use crate::rngs::StdRng;
#[doc(no_inline)]
-#[cfg(feature = "std")]
+#[cfg(all(feature = "std", feature = "std_rng"))]
pub use crate::rngs::ThreadRng;
#[doc(no_inline)] pub use crate::seq::{IteratorRandom, SliceRandom};
#[doc(no_inline)]
-#[cfg(feature = "std")]
+#[cfg(all(feature = "std", feature = "std_rng"))]
pub use crate::{random, thread_rng};
#[doc(no_inline)] pub use crate::{CryptoRng, Rng, RngCore, SeedableRng};
diff --git a/src/rng.rs b/src/rng.rs
new file mode 100644
index 0000000..bb977a5
--- /dev/null
+++ b/src/rng.rs
@@ -0,0 +1,585 @@
+// Copyright 2018 Developers of the Rand project.
+// Copyright 2013-2017 The Rust Project Developers.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! [`Rng`] trait
+
+use rand_core::{Error, RngCore};
+use crate::distributions::uniform::{SampleRange, SampleUniform};
+use crate::distributions::{self, Distribution, Standard};
+use core::num::Wrapping;
+use core::{mem, slice};
+
+/// An automatically-implemented extension trait on [`RngCore`] providing high-level
+/// generic methods for sampling values and other convenience methods.
+///
+/// This is the primary trait to use when generating random values.
+///
+/// # Generic usage
+///
+/// The basic pattern is `fn foo<R: Rng + ?Sized>(rng: &mut R)`. Some
+/// things are worth noting here:
+///
+/// - Since `Rng: RngCore` and every `RngCore` implements `Rng`, it makes no
+/// difference whether we use `R: Rng` or `R: RngCore`.
+/// - The `+ ?Sized` un-bounding allows functions to be called directly on
+/// type-erased references; i.e. `foo(r)` where `r: &mut RngCore`. Without
+/// this it would be necessary to write `foo(&mut r)`.
+///
+/// An alternative pattern is possible: `fn foo<R: Rng>(rng: R)`. This has some
+/// trade-offs. It allows the argument to be consumed directly without a `&mut`
+/// (which is how `from_rng(thread_rng())` works); also it still works directly
+/// on references (including type-erased references). Unfortunately within the
+/// function `foo` it is not known whether `rng` is a reference type or not,
+/// hence many uses of `rng` require an extra reference, either explicitly
+/// (`distr.sample(&mut rng)`) or implicitly (`rng.gen()`); one may hope the
+/// optimiser can remove redundant references later.
+///
+/// Example:
+///
+/// ```
+/// # use rand::thread_rng;
+/// use rand::Rng;
+///
+/// fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 {
+/// rng.gen()
+/// }
+///
+/// # let v = foo(&mut thread_rng());
+/// ```
+pub trait Rng: RngCore {
+ /// Return a random value supporting the [`Standard`] distribution.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::{thread_rng, Rng};
+ ///
+ /// let mut rng = thread_rng();
+ /// let x: u32 = rng.gen();
+ /// println!("{}", x);
+ /// println!("{:?}", rng.gen::<(f64, bool)>());
+ /// ```
+ ///
+ /// # Arrays and tuples
+ ///
+ /// The `rng.gen()` method is able to generate arrays (up to 32 elements)
+ /// and tuples (up to 12 elements), so long as all element types can be
+ /// generated.
+ ///
+ /// For arrays of integers, especially for those with small element types
+ /// (< 64 bit), it will likely be faster to instead use [`Rng::fill`].
+ ///
+ /// ```
+ /// use rand::{thread_rng, Rng};
+ ///
+ /// let mut rng = thread_rng();
+ /// let tuple: (u8, i32, char) = rng.gen(); // arbitrary tuple support
+ ///
+ /// let arr1: [f32; 32] = rng.gen(); // array construction
+ /// let mut arr2 = [0u8; 128];
+ /// rng.fill(&mut arr2); // array fill
+ /// ```
+ ///
+ /// [`Standard`]: distributions::Standard
+ #[inline]
+ fn gen<T>(&mut self) -> T
+ where Standard: Distribution<T> {
+ Standard.sample(self)
+ }
+
+ /// Generate a random value in the given range.
+ ///
+ /// This function is optimised for the case that only a single sample is
+ /// made from the given range. See also the [`Uniform`] distribution
+ /// type which may be faster if sampling from the same range repeatedly.
+ ///
+ /// Only `gen_range(low..high)` and `gen_range(low..=high)` are supported.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the range is empty.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::{thread_rng, Rng};
+ ///
+ /// let mut rng = thread_rng();
+ ///
+ /// // Exclusive range
+ /// let n: u32 = rng.gen_range(0..10);
+ /// println!("{}", n);
+ /// let m: f64 = rng.gen_range(-40.0..1.3e5);
+ /// println!("{}", m);
+ ///
+ /// // Inclusive range
+ /// let n: u32 = rng.gen_range(0..=10);
+ /// println!("{}", n);
+ /// ```
+ ///
+ /// [`Uniform`]: distributions::uniform::Uniform
+ fn gen_range<T, R>(&mut self, range: R) -> T
+ where
+ T: SampleUniform,
+ R: SampleRange<T>
+ {
+ assert!(!range.is_empty(), "cannot sample empty range");
+ range.sample_single(self)
+ }
+
+ /// Sample a new value, using the given distribution.
+ ///
+ /// ### Example
+ ///
+ /// ```
+ /// use rand::{thread_rng, Rng};
+ /// use rand::distributions::Uniform;
+ ///
+ /// let mut rng = thread_rng();
+ /// let x = rng.sample(Uniform::new(10u32, 15));
+ /// // Type annotation requires two types, the type and distribution; the
+ /// // distribution can be inferred.
+ /// let y = rng.sample::<u16, _>(Uniform::new(10, 15));
+ /// ```
+ fn sample<T, D: Distribution<T>>(&mut self, distr: D) -> T {
+ distr.sample(self)
+ }
+
+ /// Create an iterator that generates values using the given distribution.
+ ///
+ /// Note that this function takes its arguments by value. This works since
+ /// `(&mut R): Rng where R: Rng` and
+ /// `(&D): Distribution where D: Distribution`,
+ /// however borrowing is not automatic hence `rng.sample_iter(...)` may
+ /// need to be replaced with `(&mut rng).sample_iter(...)`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::{thread_rng, Rng};
+ /// use rand::distributions::{Alphanumeric, Uniform, Standard};
+ ///
+ /// let mut rng = thread_rng();
+ ///
+ /// // Vec of 16 x f32:
+ /// let v: Vec<f32> = (&mut rng).sample_iter(Standard).take(16).collect();
+ ///
+ /// // String:
+ /// let s: String = (&mut rng).sample_iter(Alphanumeric)
+ /// .take(7)
+ /// .map(char::from)
+ /// .collect();
+ ///
+ /// // Combined values
+ /// println!("{:?}", (&mut rng).sample_iter(Standard).take(5)
+ /// .collect::<Vec<(f64, bool)>>());
+ ///
+ /// // Dice-rolling:
+ /// let die_range = Uniform::new_inclusive(1, 6);
+ /// let mut roll_die = (&mut rng).sample_iter(die_range);
+ /// while roll_die.next().unwrap() != 6 {
+ /// println!("Not a 6; rolling again!");
+ /// }
+ /// ```
+ fn sample_iter<T, D>(self, distr: D) -> distributions::DistIter<D, Self, T>
+ where
+ D: Distribution<T>,
+ Self: Sized,
+ {
+ distr.sample_iter(self)
+ }
+
+ /// Fill any type implementing [`Fill`] with random data
+ ///
+ /// The distribution is expected to be uniform with portable results, but
+ /// this cannot be guaranteed for third-party implementations.
+ ///
+ /// This is identical to [`try_fill`] except that it panics on error.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::{thread_rng, Rng};
+ ///
+ /// let mut arr = [0i8; 20];
+ /// thread_rng().fill(&mut arr[..]);
+ /// ```
+ ///
+ /// [`fill_bytes`]: RngCore::fill_bytes
+ /// [`try_fill`]: Rng::try_fill
+ fn fill<T: Fill + ?Sized>(&mut self, dest: &mut T) {
+ dest.try_fill(self).unwrap_or_else(|_| panic!("Rng::fill failed"))
+ }
+
+ /// Fill any type implementing [`Fill`] with random data
+ ///
+ /// The distribution is expected to be uniform with portable results, but
+ /// this cannot be guaranteed for third-party implementations.
+ ///
+ /// This is identical to [`fill`] except that it forwards errors.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use rand::Error;
+ /// use rand::{thread_rng, Rng};
+ ///
+ /// # fn try_inner() -> Result<(), Error> {
+ /// let mut arr = [0u64; 4];
+ /// thread_rng().try_fill(&mut arr[..])?;
+ /// # Ok(())
+ /// # }
+ ///
+ /// # try_inner().unwrap()
+ /// ```
+ ///
+ /// [`try_fill_bytes`]: RngCore::try_fill_bytes
+ /// [`fill`]: Rng::fill
+ fn try_fill<T: Fill + ?Sized>(&mut self, dest: &mut T) -> Result<(), Error> {
+ dest.try_fill(self)
+ }
+
+ /// Return a bool with a probability `p` of being true.
+ ///
+ /// See also the [`Bernoulli`] distribution, which may be faster if
+ /// sampling from the same probability repeatedly.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::{thread_rng, Rng};
+ ///
+ /// let mut rng = thread_rng();
+ /// println!("{}", rng.gen_bool(1.0 / 3.0));
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// If `p < 0` or `p > 1`.
+ ///
+ /// [`Bernoulli`]: distributions::Bernoulli
+ #[inline]
+ fn gen_bool(&mut self, p: f64) -> bool {
+ let d = distributions::Bernoulli::new(p).unwrap();
+ self.sample(d)
+ }
+
+ /// Return a bool with a probability of `numerator/denominator` of being
+ /// true. I.e. `gen_ratio(2, 3)` has chance of 2 in 3, or about 67%, of
+ /// returning true. If `numerator == denominator`, then the returned value
+ /// is guaranteed to be `true`. If `numerator == 0`, then the returned
+ /// value is guaranteed to be `false`.
+ ///
+ /// See also the [`Bernoulli`] distribution, which may be faster if
+ /// sampling from the same `numerator` and `denominator` repeatedly.
+ ///
+ /// # Panics
+ ///
+ /// If `denominator == 0` or `numerator > denominator`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::{thread_rng, Rng};
+ ///
+ /// let mut rng = thread_rng();
+ /// println!("{}", rng.gen_ratio(2, 3));
+ /// ```
+ ///
+ /// [`Bernoulli`]: distributions::Bernoulli
+ #[inline]
+ fn gen_ratio(&mut self, numerator: u32, denominator: u32) -> bool {
+ let d = distributions::Bernoulli::from_ratio(numerator, denominator).unwrap();
+ self.sample(d)
+ }
+}
+
+impl<R: RngCore + ?Sized> Rng for R {}
+
+/// Types which may be filled with random data
+///
+/// This trait allows arrays to be efficiently filled with random data.
+///
+/// Implementations are expected to be portable across machines unless
+/// clearly documented otherwise (see the
+/// [Chapter on Portability](https://rust-random.github.io/book/portability.html)).
+pub trait Fill {
+ /// Fill self with random data
+ fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error>;
+}
+
+macro_rules! impl_fill_each {
+ () => {};
+ ($t:ty) => {
+ impl Fill for [$t] {
+ fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+ for elt in self.iter_mut() {
+ *elt = rng.gen();
+ }
+ Ok(())
+ }
+ }
+ };
+ ($t:ty, $($tt:ty,)*) => {
+ impl_fill_each!($t);
+ impl_fill_each!($($tt,)*);
+ };
+}
+
+impl_fill_each!(bool, char, f32, f64,);
+
+impl Fill for [u8] {
+ fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+ rng.try_fill_bytes(self)
+ }
+}
+
+macro_rules! impl_fill {
+ () => {};
+ ($t:ty) => {
+ impl Fill for [$t] {
+ #[inline(never)] // in micro benchmarks, this improves performance
+ fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+ if self.len() > 0 {
+ rng.try_fill_bytes(unsafe {
+ slice::from_raw_parts_mut(self.as_mut_ptr()
+ as *mut u8,
+ self.len() * mem::size_of::<$t>()
+ )
+ })?;
+ for x in self {
+ *x = x.to_le();
+ }
+ }
+ Ok(())
+ }
+ }
+
+ impl Fill for [Wrapping<$t>] {
+ #[inline(never)]
+ fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+ if self.len() > 0 {
+ rng.try_fill_bytes(unsafe {
+ slice::from_raw_parts_mut(self.as_mut_ptr()
+ as *mut u8,
+ self.len() * mem::size_of::<$t>()
+ )
+ })?;
+ for x in self {
+ *x = Wrapping(x.0.to_le());
+ }
+ }
+ Ok(())
+ }
+ }
+ };
+ ($t:ty, $($tt:ty,)*) => {
+ impl_fill!($t);
+ // TODO: this could replace above impl once Rust #32463 is fixed
+ // impl_fill!(Wrapping<$t>);
+ impl_fill!($($tt,)*);
+ }
+}
+
+impl_fill!(u16, u32, u64, usize,);
+#[cfg(not(target_os = "emscripten"))]
+impl_fill!(u128);
+impl_fill!(i8, i16, i32, i64, isize,);
+#[cfg(not(target_os = "emscripten"))]
+impl_fill!(i128);
+
+macro_rules! impl_fill_arrays {
+ ($n:expr,) => {};
+ ($n:expr, $N:ident) => {
+ impl<T> Fill for [T; $n] where [T]: Fill {
+ fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
+ self[..].try_fill(rng)
+ }
+ }
+ };
+ ($n:expr, $N:ident, $($NN:ident,)*) => {
+ impl_fill_arrays!($n, $N);
+ impl_fill_arrays!($n - 1, $($NN,)*);
+ };
+ (!div $n:expr,) => {};
+ (!div $n:expr, $N:ident, $($NN:ident,)*) => {
+ impl_fill_arrays!($n, $N);
+ impl_fill_arrays!(!div $n / 2, $($NN,)*);
+ };
+}
+#[rustfmt::skip]
+impl_fill_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,);
+impl_fill_arrays!(!div 4096, N,N,N,N,N,N,N,);
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::test::rng;
+ use crate::rngs::mock::StepRng;
+ #[cfg(feature = "alloc")] use alloc::boxed::Box;
+
+ #[test]
+ fn test_fill_bytes_default() {
+ let mut r = StepRng::new(0x11_22_33_44_55_66_77_88, 0);
+
+ // check every remainder mod 8, both in small and big vectors.
+ let lengths = [0, 1, 2, 3, 4, 5, 6, 7, 80, 81, 82, 83, 84, 85, 86, 87];
+ for &n in lengths.iter() {
+ let mut buffer = [0u8; 87];
+ let v = &mut buffer[0..n];
+ r.fill_bytes(v);
+
+ // use this to get nicer error messages.
+ for (i, &byte) in v.iter().enumerate() {
+ if byte == 0 {
+ panic!("byte {} of {} is zero", i, n)
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn test_fill() {
+ let x = 9041086907909331047; // a random u64
+ let mut rng = StepRng::new(x, 0);
+
+ // Convert to byte sequence and back to u64; byte-swap twice if BE.
+ let mut array = [0u64; 2];
+ rng.fill(&mut array[..]);
+ assert_eq!(array, [x, x]);
+ assert_eq!(rng.next_u64(), x);
+
+ // Convert to bytes then u32 in LE order
+ let mut array = [0u32; 2];
+ rng.fill(&mut array[..]);
+ assert_eq!(array, [x as u32, (x >> 32) as u32]);
+ assert_eq!(rng.next_u32(), x as u32);
+
+ // Check equivalence using wrapped arrays
+ let mut warray = [Wrapping(0u32); 2];
+ rng.fill(&mut warray[..]);
+ assert_eq!(array[0], warray[0].0);
+ assert_eq!(array[1], warray[1].0);
+
+ // Check equivalence for generated floats
+ let mut array = [0f32; 2];
+ rng.fill(&mut array);
+ let gen: [f32; 2] = rng.gen();
+ assert_eq!(array, gen);
+ }
+
+ #[test]
+ fn test_fill_empty() {
+ let mut array = [0u32; 0];
+ let mut rng = StepRng::new(0, 1);
+ rng.fill(&mut array);
+ rng.fill(&mut array[..]);
+ }
+
+ #[test]
+ fn test_gen_range_int() {
+ let mut r = rng(101);
+ for _ in 0..1000 {
+ let a = r.gen_range(-4711..17);
+ assert!(a >= -4711 && a < 17);
+ let a = r.gen_range(-3i8..42);
+ assert!(a >= -3i8 && a < 42i8);
+ let a: u16 = r.gen_range(10..99);
+ assert!(a >= 10u16 && a < 99u16);
+ let a = r.gen_range(-100i32..2000);
+ assert!(a >= -100i32 && a < 2000i32);
+ let a: u32 = r.gen_range(12..=24);
+ assert!(a >= 12u32 && a <= 24u32);
+
+ assert_eq!(r.gen_range(0u32..1), 0u32);
+ assert_eq!(r.gen_range(-12i64..-11), -12i64);
+ assert_eq!(r.gen_range(3_000_000..3_000_001), 3_000_000);
+ }
+ }
+
+ #[test]
+ fn test_gen_range_float() {
+ let mut r = rng(101);
+ for _ in 0..1000 {
+ let a = r.gen_range(-4.5..1.7);
+ assert!(a >= -4.5 && a < 1.7);
+ let a = r.gen_range(-1.1..=-0.3);
+ assert!(a >= -1.1 && a <= -0.3);
+
+ assert_eq!(r.gen_range(0.0f32..=0.0), 0.);
+ assert_eq!(r.gen_range(-11.0..=-11.0), -11.);
+ assert_eq!(r.gen_range(3_000_000.0..=3_000_000.0), 3_000_000.);
+ }
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_gen_range_panic_int() {
+ let mut r = rng(102);
+ r.gen_range(5..-2);
+ }
+
+ #[test]
+ #[should_panic]
+ fn test_gen_range_panic_usize() {
+ let mut r = rng(103);
+ r.gen_range(5..2);
+ }
+
+ #[test]
+ fn test_gen_bool() {
+ let mut r = rng(105);
+ for _ in 0..5 {
+ assert_eq!(r.gen_bool(0.0), false);
+ assert_eq!(r.gen_bool(1.0), true);
+ }
+ }
+
+ #[test]
+ fn test_rng_trait_object() {
+ use crate::distributions::{Distribution, Standard};
+ let mut rng = rng(109);
+ let mut r = &mut rng as &mut dyn RngCore;
+ r.next_u32();
+ r.gen::<i32>();
+ assert_eq!(r.gen_range(0..1), 0);
+ let _c: u8 = Standard.sample(&mut r);
+ }
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ fn test_rng_boxed_trait() {
+ use crate::distributions::{Distribution, Standard};
+ let rng = rng(110);
+ let mut r = Box::new(rng) as Box<dyn RngCore>;
+ r.next_u32();
+ r.gen::<i32>();
+ assert_eq!(r.gen_range(0..1), 0);
+ let _c: u8 = Standard.sample(&mut r);
+ }
+
+ #[test]
+ #[cfg_attr(miri, ignore)] // Miri is too slow
+ fn test_gen_ratio_average() {
+ const NUM: u32 = 3;
+ const DENOM: u32 = 10;
+ const N: u32 = 100_000;
+
+ let mut sum: u32 = 0;
+ let mut rng = rng(111);
+ for _ in 0..N {
+ if rng.gen_ratio(NUM, DENOM) {
+ sum += 1;
+ }
+ }
+ // Have Binomial(N, NUM/DENOM) distribution
+ let expected = (NUM * N) / DENOM; // exact integer
+ assert!(((sum - expected) as i32).abs() < 500);
+ }
+}
diff --git a/src/rngs/adapter/mod.rs b/src/rngs/adapter/mod.rs
index 45e56af..22b7158 100644
--- a/src/rngs/adapter/mod.rs
+++ b/src/rngs/adapter/mod.rs
@@ -8,8 +8,8 @@
//! Wrappers / adapters forming RNGs
-#[cfg(feature = "std")] mod read;
+mod read;
mod reseeding;
-#[cfg(feature = "std")] pub use self::read::{ReadError, ReadRng};
+pub use self::read::{ReadError, ReadRng};
pub use self::reseeding::ReseedingRng;
diff --git a/src/rngs/adapter/read.rs b/src/rngs/adapter/read.rs
index 9a4b55d..63b0dd0 100644
--- a/src/rngs/adapter/read.rs
+++ b/src/rngs/adapter/read.rs
@@ -103,6 +103,8 @@
#[cfg(test)]
mod test {
+ use std::println;
+
use super::ReadRng;
use crate::RngCore;
@@ -110,24 +112,24 @@
fn test_reader_rng_u64() {
// transmute from the target to avoid endianness concerns.
#[rustfmt::skip]
- let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1,
- 0 , 0, 0, 0, 0, 0, 0, 2,
- 0, 0, 0, 0, 0, 0, 0, 3];
+ let v = [0u8, 0, 0, 0, 0, 0, 0, 1,
+ 0, 4, 0, 0, 3, 0, 0, 2,
+ 5, 0, 0, 0, 0, 0, 0, 0];
let mut rng = ReadRng::new(&v[..]);
- assert_eq!(rng.next_u64(), 1_u64.to_be());
- assert_eq!(rng.next_u64(), 2_u64.to_be());
- assert_eq!(rng.next_u64(), 3_u64.to_be());
+ assert_eq!(rng.next_u64(), 1 << 56);
+ assert_eq!(rng.next_u64(), (2 << 56) + (3 << 32) + (4 << 8));
+ assert_eq!(rng.next_u64(), 5);
}
#[test]
fn test_reader_rng_u32() {
- let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3];
+ let v = [0u8, 0, 0, 1, 0, 0, 2, 0, 3, 0, 0, 0];
let mut rng = ReadRng::new(&v[..]);
- assert_eq!(rng.next_u32(), 1_u32.to_be());
- assert_eq!(rng.next_u32(), 2_u32.to_be());
- assert_eq!(rng.next_u32(), 3_u32.to_be());
+ assert_eq!(rng.next_u32(), 1 << 24);
+ assert_eq!(rng.next_u32(), 2 << 16);
+ assert_eq!(rng.next_u32(), 3);
}
#[test]
diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs
index 5460e34..1977cb3 100644
--- a/src/rngs/adapter/reseeding.rs
+++ b/src/rngs/adapter/reseeding.rs
@@ -279,7 +279,7 @@
}
-#[cfg(all(unix, feature = "std", not(target_os = "emscripten")))]
+#[cfg(all(unix, not(target_os = "emscripten")))]
mod fork {
use core::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Once;
@@ -316,7 +316,7 @@
}
}
-#[cfg(not(all(unix, feature = "std", not(target_os = "emscripten"))))]
+#[cfg(not(all(unix, not(target_os = "emscripten"))))]
mod fork {
pub fn get_fork_counter() -> usize {
0
@@ -325,6 +325,7 @@
}
+#[cfg(feature = "std_rng")]
#[cfg(test)]
mod test {
use super::ReseedingRng;
diff --git a/src/rngs/entropy.rs b/src/rngs/entropy.rs
deleted file mode 100644
index 9ad0d71..0000000
--- a/src/rngs/entropy.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2018 Developers of the Rand project.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Entropy generator, or wrapper around external generators
-
-#![allow(deprecated)] // whole module is deprecated
-
-use crate::rngs::OsRng;
-use rand_core::{CryptoRng, Error, RngCore};
-
-/// An interface returning random data from external source(s), provided
-/// specifically for securely seeding algorithmic generators (PRNGs).
-///
-/// This is deprecated. It is suggested you use [`rngs::OsRng`] instead.
-///
-/// [`rngs::OsRng`]: crate::rngs::OsRng
-#[derive(Debug)]
-#[deprecated(since = "0.7.0", note = "use rngs::OsRng instead")]
-pub struct EntropyRng {
- source: OsRng,
-}
-
-impl EntropyRng {
- /// Create a new `EntropyRng`.
- ///
- /// This method will do no system calls or other initialization routines,
- /// those are done on first use. This is done to make `new` infallible,
- /// and `try_fill_bytes` the only place to report errors.
- pub fn new() -> Self {
- EntropyRng { source: OsRng }
- }
-}
-
-impl Default for EntropyRng {
- fn default() -> Self {
- EntropyRng::new()
- }
-}
-
-impl RngCore for EntropyRng {
- fn next_u32(&mut self) -> u32 {
- self.source.next_u32()
- }
-
- fn next_u64(&mut self) -> u64 {
- self.source.next_u64()
- }
-
- fn fill_bytes(&mut self, dest: &mut [u8]) {
- self.source.fill_bytes(dest)
- }
-
- fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
- self.source.try_fill_bytes(dest)
- }
-}
-
-impl CryptoRng for EntropyRng {}
-
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn test_entropy() {
- let mut rng = EntropyRng::new();
- let n = (rng.next_u32() ^ rng.next_u32()).count_ones();
- assert!(n >= 2); // p(failure) approx 1e-7
- }
-}
diff --git a/src/rngs/mock.rs b/src/rngs/mock.rs
index 9a47264..a1745a4 100644
--- a/src/rngs/mock.rs
+++ b/src/rngs/mock.rs
@@ -10,6 +10,9 @@
use rand_core::{impls, Error, RngCore};
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// A simple implementation of `RngCore` for testing purposes.
///
/// This generates an arithmetic sequence (i.e. adds a constant each step)
@@ -24,7 +27,8 @@
/// let sample: [u64; 3] = my_rng.gen();
/// assert_eq!(sample, [2, 3, 4]);
/// ```
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct StepRng {
v: u64,
a: u64,
@@ -65,3 +69,19 @@
Ok(())
}
}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ #[cfg(feature = "serde1")]
+ fn test_serialization_step_rng() {
+ use super::StepRng;
+
+ let some_rng = StepRng::new(42, 7);
+ let de_some_rng: StepRng =
+ bincode::deserialize(&bincode::serialize(&some_rng).unwrap()).unwrap();
+ assert_eq!(some_rng.v, de_some_rng.v);
+ assert_eq!(some_rng.a, de_some_rng.a);
+
+ }
+}
diff --git a/src/rngs/mod.rs b/src/rngs/mod.rs
index 1112196..ac3c2c5 100644
--- a/src/rngs/mod.rs
+++ b/src/rngs/mod.rs
@@ -58,7 +58,7 @@
//! is local, it is typically much faster than [`OsRng`]. It should be
//! secure, though the paranoid may prefer [`OsRng`].
//! - [`StdRng`] is a CSPRNG chosen for good performance and trust of security
-//! (based on reviews, maturity and usage). The current algorithm is ChaCha20,
+//! (based on reviews, maturity and usage). The current algorithm is ChaCha12,
//! which is well established and rigorously analysed.
//! [`StdRng`] provides the algorithm used by [`ThreadRng`] but without
//! periodic reseeding.
@@ -96,21 +96,24 @@
//! [`rand_xoshiro`]: https://crates.io/crates/rand_xoshiro
//! [`rng` tag]: https://crates.io/keywords/rng
-pub mod adapter;
+#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
+#[cfg(feature = "std")] pub mod adapter;
-#[cfg(feature = "std")] mod entropy;
pub mod mock; // Public so we don't export `StepRng` directly, making it a bit
// more clear it is intended for testing.
-#[cfg(feature = "small_rng")] mod small;
-mod std;
-#[cfg(feature = "std")] pub(crate) mod thread;
-#[allow(deprecated)]
-#[cfg(feature = "std")]
-pub use self::entropy::EntropyRng;
+#[cfg(all(feature = "small_rng", target_pointer_width = "64"))]
+mod xoshiro256plusplus;
+#[cfg(all(feature = "small_rng", not(target_pointer_width = "64")))]
+mod xoshiro128plusplus;
+#[cfg(feature = "small_rng")] mod small;
+
+#[cfg(feature = "std_rng")] mod std;
+#[cfg(all(feature = "std", feature = "std_rng"))] pub(crate) mod thread;
#[cfg(feature = "small_rng")] pub use self::small::SmallRng;
-pub use self::std::StdRng;
-#[cfg(feature = "std")] pub use self::thread::ThreadRng;
+#[cfg(feature = "std_rng")] pub use self::std::StdRng;
+#[cfg(all(feature = "std", feature = "std_rng"))] pub use self::thread::ThreadRng;
+#[cfg_attr(doc_cfg, doc(cfg(feature = "getrandom")))]
#[cfg(feature = "getrandom")] pub use rand_core::OsRng;
diff --git a/src/rngs/small.rs b/src/rngs/small.rs
index d676898..fb0e0d1 100644
--- a/src/rngs/small.rs
+++ b/src/rngs/small.rs
@@ -10,33 +10,36 @@
use rand_core::{Error, RngCore, SeedableRng};
-#[cfg(all(not(target_os = "emscripten"), target_pointer_width = "64"))]
-type Rng = rand_pcg::Pcg64Mcg;
-#[cfg(not(all(not(target_os = "emscripten"), target_pointer_width = "64")))]
-type Rng = rand_pcg::Pcg32;
+#[cfg(target_pointer_width = "64")]
+type Rng = super::xoshiro256plusplus::Xoshiro256PlusPlus;
+#[cfg(not(target_pointer_width = "64"))]
+type Rng = super::xoshiro128plusplus::Xoshiro128PlusPlus;
/// A small-state, fast non-crypto PRNG
///
/// `SmallRng` may be a good choice when a PRNG with small state, cheap
/// initialization, good statistical quality and good performance are required.
-/// It is **not** a good choice when security against prediction or
-/// reproducibility are important.
-///
-/// This PRNG is **feature-gated**: to use, you must enable the crate feature
-/// `small_rng`.
+/// Note that depending on the application, [`StdRng`] may be faster on many
+/// modern platforms while providing higher-quality randomness. Furthermore,
+/// `SmallRng` is **not** a good choice when:
+/// - Security against prediction is important. Use [`StdRng`] instead.
+/// - Seeds with many zeros are provided. In such cases, it takes `SmallRng`
+/// about 10 samples to produce 0 and 1 bits with equal probability. Either
+/// provide seeds with an approximately equal number of 0 and 1 (for example
+/// by using [`SeedableRng::from_entropy`] or [`SeedableRng::seed_from_u64`]),
+/// or use [`StdRng`] instead.
///
/// The algorithm is deterministic but should not be considered reproducible
/// due to dependence on platform and possible replacement in future
/// library versions. For a reproducible generator, use a named PRNG from an
-/// external crate, e.g. [rand_pcg] or [rand_chacha].
+/// external crate, e.g. [rand_xoshiro] or [rand_chacha].
/// Refer also to [The Book](https://rust-random.github.io/book/guide-rngs.html).
///
-/// The PRNG algorithm in `SmallRng` is chosen to be
-/// efficient on the current platform, without consideration for cryptography
-/// or security. The size of its state is much smaller than [`StdRng`].
-/// The current algorithm is [`Pcg64Mcg`](rand_pcg::Pcg64Mcg) on 64-bit
-/// platforms and [`Pcg32`](rand_pcg::Pcg32) on 32-bit platforms. Both are
-/// implemented by the [rand_pcg] crate.
+/// The PRNG algorithm in `SmallRng` is chosen to be efficient on the current
+/// platform, without consideration for cryptography or security. The size of
+/// its state is much smaller than [`StdRng`]. The current algorithm is
+/// `Xoshiro256PlusPlus` on 64-bit platforms and `Xoshiro128PlusPlus` on 32-bit
+/// platforms. Both are also implemented by the [rand_xoshiro] crate.
///
/// # Examples
///
@@ -72,8 +75,9 @@
/// [`StdRng`]: crate::rngs::StdRng
/// [`thread_rng`]: crate::thread_rng
/// [rand_chacha]: https://crates.io/crates/rand_chacha
-/// [rand_pcg]: https://crates.io/crates/rand_pcg
-#[derive(Clone, Debug)]
+/// [rand_xoshiro]: https://crates.io/crates/rand_xoshiro
+#[cfg_attr(doc_cfg, doc(cfg(feature = "small_rng")))]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SmallRng(Rng);
impl RngCore for SmallRng {
diff --git a/src/rngs/std.rs b/src/rngs/std.rs
index 8b07081..80f8433 100644
--- a/src/rngs/std.rs
+++ b/src/rngs/std.rs
@@ -11,20 +11,20 @@
use crate::{CryptoRng, Error, RngCore, SeedableRng};
#[cfg(all(any(test, feature = "std"), not(target_os = "emscripten")))]
-pub(crate) use rand_chacha::ChaCha20Core as Core;
+pub(crate) use rand_chacha::ChaCha12Core as Core;
#[cfg(all(any(test, feature = "std"), target_os = "emscripten"))]
pub(crate) use rand_hc::Hc128Core as Core;
-#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha20Rng as Rng;
+#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha12Rng as Rng;
#[cfg(target_os = "emscripten")] use rand_hc::Hc128Rng as Rng;
/// The standard RNG. The PRNG algorithm in `StdRng` is chosen to be efficient
/// on the current platform, to be statistically strong and unpredictable
/// (meaning a cryptographically secure PRNG).
///
-/// The current algorithm used is the ChaCha block cipher with 20 rounds.
-/// This may change as new evidence of cipher security and performance
-/// becomes available.
+/// The current algorithm used is the ChaCha block cipher with 12 rounds. Please
+/// see this relevant [rand issue] for the discussion. This may change as new
+/// evidence of cipher security and performance becomes available.
///
/// The algorithm is deterministic but should not be considered reproducible
/// due to dependence on configuration and possible replacement in future
@@ -32,7 +32,9 @@
/// the [rand_chacha] crate directly.
///
/// [rand_chacha]: https://crates.io/crates/rand_chacha
-#[derive(Clone, Debug)]
+/// [rand issue]: https://github.com/rust-random/rand/issues/932
+#[cfg_attr(doc_cfg, doc(cfg(feature = "std_rng")))]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StdRng(Rng);
impl RngCore for StdRng {
@@ -87,9 +89,6 @@
let seed = [1,0,0,0, 23,0,0,0, 200,1,0,0, 210,30,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0];
- #[cfg(any(feature = "stdrng_strong", not(feature = "stdrng_fast")))]
- let target = [3950704604716924505, 5573172343717151650];
- #[cfg(all(not(feature = "stdrng_strong"), feature = "stdrng_fast"))]
let target = [10719222850664546238, 14064965282130556830];
let mut rng0 = StdRng::from_seed(seed);
diff --git a/src/rngs/thread.rs b/src/rngs/thread.rs
index 91ed4c3..552851f 100644
--- a/src/rngs/thread.rs
+++ b/src/rngs/thread.rs
@@ -8,8 +8,9 @@
//! Thread-local random number generator
-use std::cell::UnsafeCell;
-use std::ptr::NonNull;
+use core::cell::UnsafeCell;
+use std::rc::Rc;
+use std::thread_local;
use super::std::Core;
use crate::rngs::adapter::ReseedingRng;
@@ -36,37 +37,42 @@
// of 32 kB and less. We choose 64 kB to avoid significant overhead.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;
-/// The type returned by [`thread_rng`], essentially just a reference to the
-/// PRNG in thread-local memory.
+/// A reference to the thread-local generator
///
-/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance.
-/// As hinted by the name, the generator is thread-local. `ThreadRng` is a
-/// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`.
+/// An instance can be obtained via [`thread_rng`] or via `ThreadRng::default()`.
+/// This handle is safe to use everywhere (including thread-local destructors)
+/// but cannot be passed between threads (is not `Send` or `Sync`).
+///
+/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance
+/// and is automatically seeded from [`OsRng`].
///
/// Unlike `StdRng`, `ThreadRng` uses the [`ReseedingRng`] wrapper to reseed
-/// the PRNG from fresh entropy every 64 kiB of random data.
-/// [`OsRng`] is used to provide seed data.
-///
+/// the PRNG from fresh entropy every 64 kiB of random data as well as after a
+/// fork on Unix (though not quite immediately; see documentation of
+/// [`ReseedingRng`]).
/// Note that the reseeding is done as an extra precaution against side-channel
/// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
/// The PRNG algorithms used are assumed to be secure.
///
/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
/// [`StdRng`]: crate::rngs::StdRng
-#[derive(Copy, Clone, Debug)]
+#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
+#[derive(Clone, Debug)]
pub struct ThreadRng {
- // inner raw pointer implies type is neither Send nor Sync
- rng: NonNull<ReseedingRng<Core, OsRng>>,
+ // Rc is explictly !Send and !Sync
+ rng: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>>,
}
thread_local!(
- static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Core, OsRng>> = {
+ // We require Rc<..> to avoid premature freeing when thread_rng is used
+ // within thread-local destructors. See #968.
+ static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Core, OsRng>>> = {
let r = Core::from_rng(OsRng).unwrap_or_else(|err|
panic!("could not initialize thread_rng: {}", err));
let rng = ReseedingRng::new(r,
THREAD_RNG_RESEED_THRESHOLD,
OsRng);
- UnsafeCell::new(rng)
+ Rc::new(UnsafeCell::new(rng))
}
);
@@ -77,10 +83,10 @@
/// `ThreadRng::default()` equivalent.
///
/// For more information see [`ThreadRng`].
+#[cfg_attr(doc_cfg, doc(cfg(all(feature = "std", feature = "std_rng"))))]
pub fn thread_rng() -> ThreadRng {
- let raw = THREAD_RNG_KEY.with(|t| t.get());
- let nn = NonNull::new(raw).unwrap();
- ThreadRng { rng: nn }
+ let rng = THREAD_RNG_KEY.with(|t| t.clone());
+ ThreadRng { rng }
}
impl Default for ThreadRng {
@@ -92,20 +98,32 @@
impl RngCore for ThreadRng {
#[inline(always)]
fn next_u32(&mut self) -> u32 {
- unsafe { self.rng.as_mut().next_u32() }
+ // SAFETY: We must make sure to stop using `rng` before anyone else
+ // creates another mutable reference
+ let rng = unsafe { &mut *self.rng.get() };
+ rng.next_u32()
}
#[inline(always)]
fn next_u64(&mut self) -> u64 {
- unsafe { self.rng.as_mut().next_u64() }
+ // SAFETY: We must make sure to stop using `rng` before anyone else
+ // creates another mutable reference
+ let rng = unsafe { &mut *self.rng.get() };
+ rng.next_u64()
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
- unsafe { self.rng.as_mut().fill_bytes(dest) }
+ // SAFETY: We must make sure to stop using `rng` before anyone else
+ // creates another mutable reference
+ let rng = unsafe { &mut *self.rng.get() };
+ rng.fill_bytes(dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
- unsafe { self.rng.as_mut().try_fill_bytes(dest) }
+ // SAFETY: We must make sure to stop using `rng` before anyone else
+ // creates another mutable reference
+ let rng = unsafe { &mut *self.rng.get() };
+ rng.try_fill_bytes(dest)
}
}
@@ -119,6 +137,6 @@
use crate::Rng;
let mut r = crate::thread_rng();
r.gen::<i32>();
- assert_eq!(r.gen_range(0, 1), 0);
+ assert_eq!(r.gen_range(0..1), 0);
}
}
diff --git a/src/rngs/xoshiro128plusplus.rs b/src/rngs/xoshiro128plusplus.rs
new file mode 100644
index 0000000..ece98fa
--- /dev/null
+++ b/src/rngs/xoshiro128plusplus.rs
@@ -0,0 +1,118 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
+use rand_core::impls::{next_u64_via_u32, fill_bytes_via_next};
+use rand_core::le::read_u32_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+/// A xoshiro128++ random number generator.
+///
+/// The xoshiro128++ algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoshiro128plusplus.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct Xoshiro128PlusPlus {
+ s: [u32; 4],
+}
+
+impl SeedableRng for Xoshiro128PlusPlus {
+ type Seed = [u8; 16];
+
+ /// Create a new `Xoshiro128PlusPlus`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ #[inline]
+ fn from_seed(seed: [u8; 16]) -> Xoshiro128PlusPlus {
+ if seed.iter().all(|&x| x == 0) {
+ return Self::seed_from_u64(0);
+ }
+ let mut state = [0; 4];
+ read_u32_into(&seed, &mut state);
+ Xoshiro128PlusPlus { s: state }
+ }
+
+ /// Create a new `Xoshiro128PlusPlus` from a `u64` seed.
+ ///
+ /// This uses the SplitMix64 generator internally.
+ fn seed_from_u64(mut state: u64) -> Self {
+ const PHI: u64 = 0x9e3779b97f4a7c15;
+ let mut seed = Self::Seed::default();
+ for chunk in seed.as_mut().chunks_mut(8) {
+ state = state.wrapping_add(PHI);
+ let mut z = state;
+ z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
+ z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
+ z = z ^ (z >> 31);
+ chunk.copy_from_slice(&z.to_le_bytes());
+ }
+ Self::from_seed(seed)
+ }
+}
+
+impl RngCore for Xoshiro128PlusPlus {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ let result_starstar = self.s[0]
+ .wrapping_add(self.s[3])
+ .rotate_left(7)
+ .wrapping_add(self.s[0]);
+
+ let t = self.s[1] << 9;
+
+ self.s[2] ^= self.s[0];
+ self.s[3] ^= self.s[1];
+ self.s[1] ^= self.s[2];
+ self.s[0] ^= self.s[3];
+
+ self.s[2] ^= t;
+
+ self.s[3] = self.s[3].rotate_left(11);
+
+ result_starstar
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ next_u64_via_u32(self)
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoshiro128PlusPlus::from_seed(
+ [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro128plusplus.c
+ let expected = [
+ 641, 1573767, 3222811527, 3517856514, 836907274, 4247214768,
+ 3867114732, 1355841295, 495546011, 621204420,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u32(), e);
+ }
+ }
+}
diff --git a/src/rngs/xoshiro256plusplus.rs b/src/rngs/xoshiro256plusplus.rs
new file mode 100644
index 0000000..cd373c3
--- /dev/null
+++ b/src/rngs/xoshiro256plusplus.rs
@@ -0,0 +1,122 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
+use rand_core::impls::fill_bytes_via_next;
+use rand_core::le::read_u64_into;
+use rand_core::{SeedableRng, RngCore, Error};
+
+/// A xoshiro256** random number generator.
+///
+/// The xoshiro256** algorithm is not suitable for cryptographic purposes, but
+/// is very fast and has excellent statistical properties.
+///
+/// The algorithm used here is translated from [the `xoshiro256plusplus.c`
+/// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by
+/// David Blackman and Sebastiano Vigna.
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
+pub struct Xoshiro256PlusPlus {
+ s: [u64; 4],
+}
+
+impl SeedableRng for Xoshiro256PlusPlus {
+ type Seed = [u8; 32];
+
+ /// Create a new `Xoshiro256PlusPlus`. If `seed` is entirely 0, it will be
+ /// mapped to a different seed.
+ #[inline]
+ fn from_seed(seed: [u8; 32]) -> Xoshiro256PlusPlus {
+ if seed.iter().all(|&x| x == 0) {
+ return Self::seed_from_u64(0);
+ }
+ let mut state = [0; 4];
+ read_u64_into(&seed, &mut state);
+ Xoshiro256PlusPlus { s: state }
+ }
+
+ /// Create a new `Xoshiro256PlusPlus` from a `u64` seed.
+ ///
+ /// This uses the SplitMix64 generator internally.
+ fn seed_from_u64(mut state: u64) -> Self {
+ const PHI: u64 = 0x9e3779b97f4a7c15;
+ let mut seed = Self::Seed::default();
+ for chunk in seed.as_mut().chunks_mut(8) {
+ state = state.wrapping_add(PHI);
+ let mut z = state;
+ z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
+ z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
+ z = z ^ (z >> 31);
+ chunk.copy_from_slice(&z.to_le_bytes());
+ }
+ Self::from_seed(seed)
+ }
+}
+
+impl RngCore for Xoshiro256PlusPlus {
+ #[inline]
+ fn next_u32(&mut self) -> u32 {
+ // The lowest bits have some linear dependencies, so we use the
+ // upper bits instead.
+ (self.next_u64() >> 32) as u32
+ }
+
+ #[inline]
+ fn next_u64(&mut self) -> u64 {
+ let result_plusplus = self.s[0]
+ .wrapping_add(self.s[3])
+ .rotate_left(23)
+ .wrapping_add(self.s[0]);
+
+ let t = self.s[1] << 17;
+
+ self.s[2] ^= self.s[0];
+ self.s[3] ^= self.s[1];
+ self.s[1] ^= self.s[2];
+ self.s[0] ^= self.s[3];
+
+ self.s[2] ^= t;
+
+ self.s[3] = self.s[3].rotate_left(45);
+
+ result_plusplus
+ }
+
+ #[inline]
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ fill_bytes_via_next(self, dest);
+ }
+
+ #[inline]
+ fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
+ self.fill_bytes(dest);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reference() {
+ let mut rng = Xoshiro256PlusPlus::from_seed(
+ [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, 0, 0, 0]);
+ // These values were produced with the reference implementation:
+ // http://xoshiro.di.unimi.it/xoshiro256plusplus.c
+ let expected = [
+ 41943041, 58720359, 3588806011781223, 3591011842654386,
+ 9228616714210784205, 9973669472204895162, 14011001112246962877,
+ 12406186145184390807, 15849039046786891736, 10450023813501588000,
+ ];
+ for &e in &expected {
+ assert_eq!(rng.next_u64(), e);
+ }
+ }
+}
diff --git a/src/seq/index.rs b/src/seq/index.rs
index 551d409..c09e580 100644
--- a/src/seq/index.rs
+++ b/src/seq/index.rs
@@ -10,22 +10,24 @@
#[cfg(feature = "alloc")] use core::slice;
-#[cfg(all(feature = "alloc", not(feature = "std")))]
-use crate::alloc::vec::{self, Vec};
-#[cfg(feature = "std")] use std::vec;
+#[cfg(feature = "alloc")] use alloc::vec::{self, Vec};
// BTreeMap is not as fast in tests, but better than nothing.
#[cfg(all(feature = "alloc", not(feature = "std")))]
-use crate::alloc::collections::BTreeSet;
+use alloc::collections::BTreeSet;
#[cfg(feature = "std")] use std::collections::HashSet;
#[cfg(feature = "alloc")]
-use crate::distributions::{uniform::SampleUniform, Distribution, Uniform};
+use crate::distributions::{uniform::SampleUniform, Distribution, Uniform, WeightedError};
use crate::Rng;
+#[cfg(feature = "serde1")]
+use serde::{Serialize, Deserialize};
+
/// A vector of indices.
///
/// Multiple internal representations are possible.
#[derive(Clone, Debug)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum IndexVec {
#[doc(hidden)]
U32(Vec<u32>),
@@ -81,10 +83,15 @@
IndexVec::USize(ref v) => IndexVecIter::USize(v.iter()),
}
}
+}
+
+impl IntoIterator for IndexVec {
+ type Item = usize;
+ type IntoIter = IndexVecIntoIter;
/// Convert into an iterator over the indices as a sequence of `usize` values
#[inline]
- pub fn into_iter(self) -> IndexVecIntoIter {
+ fn into_iter(self) -> IndexVecIntoIter {
match self {
IndexVec::U32(v) => IndexVecIntoIter::U32(v.into_iter()),
IndexVec::USize(v) => IndexVecIntoIter::USize(v.into_iter()),
@@ -249,6 +256,154 @@
}
}
+/// Randomly sample exactly `amount` distinct indices from `0..length`, and
+/// return them in an arbitrary order (there is no guarantee of shuffling or
+/// ordering). The weights are to be provided by the input function `weights`,
+/// which will be called once for each index.
+///
+/// This method is used internally by the slice sampling methods, but it can
+/// sometimes be useful to have the indices themselves so this is provided as
+/// an alternative.
+///
+/// This implementation uses `O(length + amount)` space and `O(length)` time
+/// if the "nightly" feature is enabled, or `O(length)` space and
+/// `O(length + amount * log length)` time otherwise.
+///
+/// Panics if `amount > length`.
+pub fn sample_weighted<R, F, X>(
+ rng: &mut R, length: usize, weight: F, amount: usize,
+) -> Result<IndexVec, WeightedError>
+where
+ R: Rng + ?Sized,
+ F: Fn(usize) -> X,
+ X: Into<f64>,
+{
+ if length > (core::u32::MAX as usize) {
+ sample_efraimidis_spirakis(rng, length, weight, amount)
+ } else {
+ assert!(amount <= core::u32::MAX as usize);
+ let amount = amount as u32;
+ let length = length as u32;
+ sample_efraimidis_spirakis(rng, length, weight, amount)
+ }
+}
+
+
+/// Randomly sample exactly `amount` distinct indices from `0..length`, and
+/// return them in an arbitrary order (there is no guarantee of shuffling or
+/// ordering). The weights are to be provided by the input function `weights`,
+/// which will be called once for each index.
+///
+/// This implementation uses the algorithm described by Efraimidis and Spirakis
+/// in this paper: https://doi.org/10.1016/j.ipl.2005.11.003
+/// It uses `O(length + amount)` space and `O(length)` time if the
+/// "nightly" feature is enabled, or `O(length)` space and `O(length
+/// + amount * log length)` time otherwise.
+///
+/// Panics if `amount > length`.
+fn sample_efraimidis_spirakis<R, F, X, N>(
+ rng: &mut R, length: N, weight: F, amount: N,
+) -> Result<IndexVec, WeightedError>
+where
+ R: Rng + ?Sized,
+ F: Fn(usize) -> X,
+ X: Into<f64>,
+ N: UInt,
+ IndexVec: From<Vec<N>>,
+{
+ if amount == N::zero() {
+ return Ok(IndexVec::U32(Vec::new()));
+ }
+
+ if amount > length {
+ panic!("`amount` of samples must be less than or equal to `length`");
+ }
+
+ struct Element<N> {
+ index: N,
+ key: f64,
+ }
+ impl<N> PartialOrd for Element<N> {
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ self.key.partial_cmp(&other.key)
+ }
+ }
+ impl<N> Ord for Element<N> {
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ // partial_cmp will always produce a value,
+ // because we check that the weights are not nan
+ self.partial_cmp(other).unwrap()
+ }
+ }
+ impl<N> PartialEq for Element<N> {
+ fn eq(&self, other: &Self) -> bool {
+ self.key == other.key
+ }
+ }
+ impl<N> Eq for Element<N> {}
+
+ #[cfg(feature = "nightly")]
+ {
+ let mut candidates = Vec::with_capacity(length.as_usize());
+ let mut index = N::zero();
+ while index < length {
+ let weight = weight(index.as_usize()).into();
+ if !(weight >= 0.) {
+ return Err(WeightedError::InvalidWeight);
+ }
+
+ let key = rng.gen::<f64>().powf(1.0 / weight);
+ candidates.push(Element { index, key });
+
+ index += N::one();
+ }
+
+ // Partially sort the array to find the `amount` elements with the greatest
+ // keys. Do this by using `select_nth_unstable` to put the elements with
+ // the *smallest* keys at the beginning of the list in `O(n)` time, which
+ // provides equivalent information about the elements with the *greatest* keys.
+ let (_, mid, greater)
+ = candidates.select_nth_unstable(length.as_usize() - amount.as_usize());
+
+ let mut result: Vec<N> = Vec::with_capacity(amount.as_usize());
+ result.push(mid.index);
+ for element in greater {
+ result.push(element.index);
+ }
+ Ok(IndexVec::from(result))
+ }
+
+ #[cfg(not(feature = "nightly"))]
+ {
+ #[cfg(all(feature = "alloc", not(feature = "std")))]
+ use crate::alloc::collections::BinaryHeap;
+ #[cfg(feature = "std")]
+ use std::collections::BinaryHeap;
+
+ // Partially sort the array such that the `amount` elements with the largest
+ // keys are first using a binary max heap.
+ let mut candidates = BinaryHeap::with_capacity(length.as_usize());
+ let mut index = N::zero();
+ while index < length {
+ let weight = weight(index.as_usize()).into();
+ if !(weight >= 0.) {
+ return Err(WeightedError::InvalidWeight);
+ }
+
+ let key = rng.gen::<f64>().powf(1.0 / weight);
+ candidates.push(Element { index, key });
+
+ index += N::one();
+ }
+
+ let mut result: Vec<N> = Vec::with_capacity(amount.as_usize());
+ while result.len() < amount.as_usize() {
+ result.push(candidates.pop().unwrap().index);
+ }
+ Ok(IndexVec::from(result))
+ }
+}
+
/// Randomly sample exactly `amount` indices from `0..length`, using Floyd's
/// combination algorithm.
///
@@ -265,7 +420,7 @@
debug_assert!(amount <= length);
let mut indices = Vec::with_capacity(amount as usize);
for j in length - amount..length {
- let t = rng.gen_range(0, j + 1);
+ let t = rng.gen_range(0..=j);
if floyd_shuffle {
if let Some(pos) = indices.iter().position(|&x| x == t) {
indices.insert(pos, j);
@@ -281,7 +436,7 @@
// Reimplement SliceRandom::shuffle with smaller indices
for i in (1..amount).rev() {
// invariant: elements with index > i have been locked in place.
- indices.swap(i as usize, rng.gen_range(0, i + 1) as usize);
+ indices.swap(i as usize, rng.gen_range(0..=i) as usize);
}
}
IndexVec::from(indices)
@@ -305,7 +460,7 @@
let mut indices: Vec<u32> = Vec::with_capacity(length as usize);
indices.extend(0..length);
for i in 0..amount {
- let j: u32 = rng.gen_range(i, length);
+ let j: u32 = rng.gen_range(i..length);
indices.swap(i as usize, j as usize);
}
indices.truncate(amount as usize);
@@ -313,8 +468,10 @@
IndexVec::from(indices)
}
-trait UInt: Copy + PartialOrd + Ord + PartialEq + Eq + SampleUniform + core::hash::Hash {
+trait UInt: Copy + PartialOrd + Ord + PartialEq + Eq + SampleUniform
+ + core::hash::Hash + core::ops::AddAssign {
fn zero() -> Self;
+ fn one() -> Self;
fn as_usize(self) -> usize;
}
impl UInt for u32 {
@@ -324,6 +481,11 @@
}
#[inline]
+ fn one() -> Self {
+ 1
+ }
+
+ #[inline]
fn as_usize(self) -> usize {
self as usize
}
@@ -335,6 +497,11 @@
}
#[inline]
+ fn one() -> Self {
+ 1
+ }
+
+ #[inline]
fn as_usize(self) -> usize {
self
}
@@ -376,8 +543,24 @@
#[cfg(test)]
mod test {
use super::*;
- #[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec;
- #[cfg(feature = "std")] use std::vec;
+
+ #[test]
+ #[cfg(feature = "serde1")]
+ fn test_serialization_index_vec() {
+ let some_index_vec = IndexVec::from(vec![254_usize, 234, 2, 1]);
+ let de_some_index_vec: IndexVec = bincode::deserialize(&bincode::serialize(&some_index_vec).unwrap()).unwrap();
+ match (some_index_vec, de_some_index_vec) {
+ (IndexVec::U32(a), IndexVec::U32(b)) => {
+ assert_eq!(a, b);
+ },
+ (IndexVec::USize(a), IndexVec::USize(b)) => {
+ assert_eq!(a, b);
+ },
+ _ => {panic!("failed to seralize/deserialize `IndexVec`")}
+ }
+ }
+
+ #[cfg(feature = "alloc")] use alloc::vec;
#[test]
fn test_sample_boundaries() {
@@ -435,4 +618,58 @@
assert!(v1.iter().all(|e| e < length));
assert_eq!(v1, v2);
}
+
+ #[test]
+ fn test_sample_weighted() {
+ let seed_rng = crate::test::rng;
+ for &(amount, len) in &[(0, 10), (5, 10), (10, 10)] {
+ let v = sample_weighted(&mut seed_rng(423), len, |i| i as f64, amount).unwrap();
+ match v {
+ IndexVec::U32(mut indices) => {
+ assert_eq!(indices.len(), amount);
+ indices.sort();
+ indices.dedup();
+ assert_eq!(indices.len(), amount);
+ for &i in &indices {
+ assert!((i as usize) < len);
+ }
+ },
+ IndexVec::USize(_) => panic!("expected `IndexVec::U32`"),
+ }
+ }
+ }
+
+ #[test]
+ fn value_stability_sample() {
+ let do_test = |length, amount, values: &[u32]| {
+ let mut buf = [0u32; 8];
+ let mut rng = crate::test::rng(410);
+
+ let res = sample(&mut rng, length, amount);
+ let len = res.len().min(buf.len());
+ for (x, y) in res.into_iter().zip(buf.iter_mut()) {
+ *y = x as u32;
+ }
+ assert_eq!(
+ &buf[0..len],
+ values,
+ "failed sampling {}, {}",
+ length,
+ amount
+ );
+ };
+
+ do_test(10, 6, &[8, 0, 3, 5, 9, 6]); // floyd
+ do_test(25, 10, &[18, 15, 14, 9, 0, 13, 5, 24]); // floyd
+ do_test(300, 8, &[30, 283, 150, 1, 73, 13, 285, 35]); // floyd
+ do_test(300, 80, &[31, 289, 248, 154, 5, 78, 19, 286]); // inplace
+ do_test(300, 180, &[31, 289, 248, 154, 5, 78, 19, 286]); // inplace
+
+ do_test(1000_000, 8, &[
+ 103717, 963485, 826422, 509101, 736394, 807035, 5327, 632573,
+ ]); // floyd
+ do_test(1000_000, 180, &[
+ 103718, 963490, 826426, 509103, 736396, 807036, 5327, 632573,
+ ]); // rejection
+ }
}
diff --git a/src/seq/mod.rs b/src/seq/mod.rs
index dabf329..9e6ffaf 100644
--- a/src/seq/mod.rs
+++ b/src/seq/mod.rs
@@ -17,19 +17,21 @@
//!
//! Also see:
//!
-//! * [`crate::distributions::weighted`] module which provides
-//! implementations of weighted index sampling.
+//! * [`crate::distributions::WeightedIndex`] distribution which provides
+//! weighted index sampling.
//!
//! In order to make results reproducible across 32-64 bit architectures, all
//! `usize` indices are sampled as a `u32` where possible (also providing a
//! small performance boost in some cases).
-#[cfg(feature = "alloc")] pub mod index;
+#[cfg(feature = "alloc")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
+pub mod index;
#[cfg(feature = "alloc")] use core::ops::Index;
-#[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec::Vec;
+#[cfg(feature = "alloc")] use alloc::vec::Vec;
#[cfg(feature = "alloc")]
use crate::distributions::uniform::{SampleBorrow, SampleUniform};
@@ -44,13 +46,11 @@
/// ```
/// use rand::seq::SliceRandom;
///
-/// fn main() {
-/// let mut rng = rand::thread_rng();
-/// let mut bytes = "Hello, random!".to_string().into_bytes();
-/// bytes.shuffle(&mut rng);
-/// let str = String::from_utf8(bytes).unwrap();
-/// println!("{}", str);
-/// }
+/// let mut rng = rand::thread_rng();
+/// let mut bytes = "Hello, random!".to_string().into_bytes();
+/// bytes.shuffle(&mut rng);
+/// let str = String::from_utf8(bytes).unwrap();
+/// println!("{}", str);
/// ```
/// Example output (non-deterministic):
/// ```none
@@ -111,6 +111,7 @@
/// }
/// ```
#[cfg(feature = "alloc")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
fn choose_multiple<R>(&self, rng: &mut R, amount: usize) -> SliceChooseIter<Self, Self::Item>
where R: Rng + ?Sized;
@@ -138,6 +139,7 @@
/// [`choose_weighted_mut`]: SliceRandom::choose_weighted_mut
/// [`distributions::weighted`]: crate::distributions::weighted
#[cfg(feature = "alloc")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
fn choose_weighted<R, F, B, X>(
&self, rng: &mut R, weight: F,
) -> Result<&Self::Item, WeightedError>
@@ -165,6 +167,7 @@
/// [`choose_weighted`]: SliceRandom::choose_weighted
/// [`distributions::weighted`]: crate::distributions::weighted
#[cfg(feature = "alloc")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
fn choose_weighted_mut<R, F, B, X>(
&mut self, rng: &mut R, weight: F,
) -> Result<&mut Self::Item, WeightedError>
@@ -178,6 +181,46 @@
+ Clone
+ Default;
+ /// Similar to [`choose_multiple`], but where the likelihood of each element's
+ /// inclusion in the output may be specified. The elements are returned in an
+ /// arbitrary, unspecified order.
+ ///
+ /// The specified function `weight` maps each item `x` to a relative
+ /// likelihood `weight(x)`. The probability of each item being selected is
+ /// therefore `weight(x) / s`, where `s` is the sum of all `weight(x)`.
+ ///
+ /// If all of the weights are equal, even if they are all zero, each element has
+ /// an equal likelihood of being selected.
+ ///
+ /// The complexity of this method depends on the feature `partition_at_index`.
+ /// If the feature is enabled, then for slices of length `n`, the complexity
+ /// is `O(n)` space and `O(n)` time. Otherwise, the complexity is `O(n)` space and
+ /// `O(n * log amount)` time.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use rand::prelude::*;
+ ///
+ /// let choices = [('a', 2), ('b', 1), ('c', 1)];
+ /// let mut rng = thread_rng();
+ /// // First Draw * Second Draw = total odds
+ /// // -----------------------
+ /// // (50% * 50%) + (25% * 67%) = 41.7% chance that the output is `['a', 'b']` in some order.
+ /// // (50% * 50%) + (25% * 67%) = 41.7% chance that the output is `['a', 'c']` in some order.
+ /// // (25% * 33%) + (25% * 33%) = 16.6% chance that the output is `['b', 'c']` in some order.
+ /// println!("{:?}", choices.choose_multiple_weighted(&mut rng, 2, |item| item.1).unwrap().collect::<Vec<_>>());
+ /// ```
+ /// [`choose_multiple`]: SliceRandom::choose_multiple
+ #[cfg(feature = "alloc")]
+ fn choose_multiple_weighted<R, F, X>(
+ &self, rng: &mut R, amount: usize, weight: F,
+ ) -> Result<SliceChooseIter<Self, Self::Item>, WeightedError>
+ where
+ R: Rng + ?Sized,
+ F: Fn(&Self::Item) -> X,
+ X: Into<f64>;
+
/// Shuffle a mutable slice in place.
///
/// For slices of length `n`, complexity is `O(n)`.
@@ -222,18 +265,17 @@
/// Extension trait on iterators, providing random sampling methods.
///
-/// This trait is implemented on all sized iterators, providing methods for
+/// This trait is implemented on all iterators `I` where `I: Iterator + Sized`
+/// and provides methods for
/// choosing one or more elements. You must `use` this trait:
///
/// ```
/// use rand::seq::IteratorRandom;
///
-/// fn main() {
-/// let mut rng = rand::thread_rng();
-///
-/// let faces = "😀😎😐😕😠😢";
-/// println!("I am {}!", faces.chars().choose(&mut rng).unwrap());
-/// }
+/// let mut rng = rand::thread_rng();
+///
+/// let faces = "😀😎😐😕😠😢";
+/// println!("I am {}!", faces.chars().choose(&mut rng).unwrap());
/// ```
/// Example output (non-deterministic):
/// ```none
@@ -250,14 +292,20 @@
/// available, complexity is `O(n)` where `n` is the iterator length.
/// Partial hints (where `lower > 0`) also improve performance.
///
- /// For slices, prefer [`SliceRandom::choose`] which guarantees `O(1)`
- /// performance.
+ /// Note that the output values and the number of RNG samples used
+ /// depends on size hints. In particular, `Iterator` combinators that don't
+ /// change the values yielded but change the size hints may result in
+ /// `choose` returning different elements. If you want consistent results
+ /// and RNG usage consider using [`IteratorRandom::choose_stable`].
fn choose<R>(mut self, rng: &mut R) -> Option<Self::Item>
where R: Rng + ?Sized {
let (mut lower, mut upper) = self.size_hint();
let mut consumed = 0;
let mut result = None;
+ // Handling for this condition outside the loop allows the optimizer to eliminate the loop
+ // when the Iterator is an ExactSizeIterator. This has a large performance impact on e.g.
+ // seq_iter_choose_from_1000.
if upper == Some(lower) {
return if lower == 0 {
None
@@ -289,8 +337,7 @@
return result;
}
consumed += 1;
- let denom = consumed as f64; // accurate to 2^53 elements
- if rng.gen_bool(1.0 / denom) {
+ if gen_index(rng, consumed) == 0 {
result = elem;
}
}
@@ -301,6 +348,64 @@
}
}
+ /// Choose one element at random from the iterator.
+ ///
+ /// Returns `None` if and only if the iterator is empty.
+ ///
+ /// This method is very similar to [`choose`] except that the result
+ /// only depends on the length of the iterator and the values produced by
+ /// `rng`. Notably for any iterator of a given length this will make the
+ /// same requests to `rng` and if the same sequence of values are produced
+ /// the same index will be selected from `self`. This may be useful if you
+ /// need consistent results no matter what type of iterator you are working
+ /// with. If you do not need this stability prefer [`choose`].
+ ///
+ /// Note that this method still uses [`Iterator::size_hint`] to skip
+ /// constructing elements where possible, however the selection and `rng`
+ /// calls are the same in the face of this optimization. If you want to
+ /// force every element to be created regardless call `.inspect(|e| ())`.
+ ///
+ /// [`choose`]: IteratorRandom::choose
+ fn choose_stable<R>(mut self, rng: &mut R) -> Option<Self::Item>
+ where R: Rng + ?Sized {
+ let mut consumed = 0;
+ let mut result = None;
+
+ loop {
+ // Currently the only way to skip elements is `nth()`. So we need to
+ // store what index to access next here.
+ // This should be replaced by `advance_by()` once it is stable:
+ // https://github.com/rust-lang/rust/issues/77404
+ let mut next = 0;
+
+ let (lower, _) = self.size_hint();
+ if lower >= 2 {
+ let highest_selected = (0..lower)
+ .filter(|ix| gen_index(rng, consumed+ix+1) == 0)
+ .last();
+
+ consumed += lower;
+ next = lower;
+
+ if let Some(ix) = highest_selected {
+ result = self.nth(ix);
+ next -= ix + 1;
+ debug_assert!(result.is_some(), "iterator shorter than size_hint().0");
+ }
+ }
+
+ let elem = self.nth(next);
+ if elem.is_none() {
+ return result
+ }
+
+ if gen_index(rng, consumed+1) == 0 {
+ result = elem;
+ }
+ consumed += 1;
+ }
+ }
+
/// Collects values at random from the iterator into a supplied buffer
/// until that buffer is filled.
///
@@ -353,6 +458,7 @@
/// Complexity is `O(n)` where `n` is the length of the iterator.
/// For slices, prefer [`SliceRandom::choose_multiple`].
#[cfg(feature = "alloc")]
+ #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
fn choose_multiple<R>(mut self, rng: &mut R, amount: usize) -> Vec<Self::Item>
where R: Rng + ?Sized {
let mut reservoir = Vec::with_capacity(amount);
@@ -450,6 +556,29 @@
Ok(&mut self[distr.sample(rng)])
}
+ #[cfg(feature = "alloc")]
+ fn choose_multiple_weighted<R, F, X>(
+ &self, rng: &mut R, amount: usize, weight: F,
+ ) -> Result<SliceChooseIter<Self, Self::Item>, WeightedError>
+ where
+ R: Rng + ?Sized,
+ F: Fn(&Self::Item) -> X,
+ X: Into<f64>,
+ {
+ let amount = ::core::cmp::min(amount, self.len());
+ Ok(SliceChooseIter {
+ slice: self,
+ _phantom: Default::default(),
+ indices: index::sample_weighted(
+ rng,
+ self.len(),
+ |idx| weight(&self[idx]).into(),
+ amount,
+ )?
+ .into_iter(),
+ })
+ }
+
fn shuffle<R>(&mut self, rng: &mut R)
where R: Rng + ?Sized {
for i in (1..self.len()).rev() {
@@ -487,6 +616,7 @@
/// This struct is created by
/// [`SliceRandom::choose_multiple`](trait.SliceRandom.html#tymethod.choose_multiple).
#[cfg(feature = "alloc")]
+#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[derive(Debug)]
pub struct SliceChooseIter<'a, S: ?Sized + 'a, T: 'a> {
slice: &'a S,
@@ -524,9 +654,9 @@
#[inline]
fn gen_index<R: Rng + ?Sized>(rng: &mut R, ubound: usize) -> usize {
if ubound <= (core::u32::MAX as usize) {
- rng.gen_range(0, ubound as u32) as usize
+ rng.gen_range(0..ubound as u32) as usize
} else {
- rng.gen_range(0, ubound)
+ rng.gen_range(0..ubound)
}
}
@@ -567,6 +697,40 @@
assert_eq!(v.choose_mut(&mut r), None);
}
+ #[test]
+ fn value_stability_slice() {
+ let mut r = crate::test::rng(413);
+ let chars = [
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ ];
+ let mut nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+
+ assert_eq!(chars.choose(&mut r), Some(&'l'));
+ assert_eq!(nums.choose_mut(&mut r), Some(&mut 10));
+
+ #[cfg(feature = "alloc")]
+ assert_eq!(
+ &chars
+ .choose_multiple(&mut r, 8)
+ .cloned()
+ .collect::<Vec<char>>(),
+ &['d', 'm', 'b', 'n', 'c', 'k', 'h', 'e']
+ );
+
+ #[cfg(feature = "alloc")]
+ assert_eq!(chars.choose_weighted(&mut r, |_| 1), Ok(&'f'));
+ #[cfg(feature = "alloc")]
+ assert_eq!(nums.choose_weighted_mut(&mut r, |_| 1), Ok(&mut 5));
+
+ let mut r = crate::test::rng(414);
+ nums.shuffle(&mut r);
+ assert_eq!(nums, [9, 5, 3, 10, 7, 12, 8, 11, 6, 4, 0, 2, 1]);
+ nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
+ let res = nums.partial_shuffle(&mut r, 6);
+ assert_eq!(res.0, &mut [7, 4, 8, 6, 9, 3]);
+ assert_eq!(res.1, &mut [0, 1, 2, 12, 11, 5, 10]);
+ }
+
#[derive(Clone)]
struct UnhintedIterator<I: Iterator + Clone> {
iter: I,
@@ -691,6 +855,103 @@
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
+ fn test_iterator_choose_stable() {
+ let r = &mut crate::test::rng(109);
+ fn test_iter<R: Rng + ?Sized, Iter: Iterator<Item = usize> + Clone>(r: &mut R, iter: Iter) {
+ let mut chosen = [0i32; 9];
+ for _ in 0..1000 {
+ let picked = iter.clone().choose_stable(r).unwrap();
+ chosen[picked] += 1;
+ }
+ for count in chosen.iter() {
+ // Samples should follow Binomial(1000, 1/9)
+ // Octave: binopdf(x, 1000, 1/9) gives the prob of *count == x
+ // Note: have seen 153, which is unlikely but not impossible.
+ assert!(
+ 72 < *count && *count < 154,
+ "count not close to 1000/9: {}",
+ count
+ );
+ }
+ }
+
+ test_iter(r, 0..9);
+ test_iter(r, [0, 1, 2, 3, 4, 5, 6, 7, 8].iter().cloned());
+ #[cfg(feature = "alloc")]
+ test_iter(r, (0..9).collect::<Vec<_>>().into_iter());
+ test_iter(r, UnhintedIterator { iter: 0..9 });
+ test_iter(r, ChunkHintedIterator {
+ iter: 0..9,
+ chunk_size: 4,
+ chunk_remaining: 4,
+ hint_total_size: false,
+ });
+ test_iter(r, ChunkHintedIterator {
+ iter: 0..9,
+ chunk_size: 4,
+ chunk_remaining: 4,
+ hint_total_size: true,
+ });
+ test_iter(r, WindowHintedIterator {
+ iter: 0..9,
+ window_size: 2,
+ hint_total_size: false,
+ });
+ test_iter(r, WindowHintedIterator {
+ iter: 0..9,
+ window_size: 2,
+ hint_total_size: true,
+ });
+
+ assert_eq!((0..0).choose(r), None);
+ assert_eq!(UnhintedIterator { iter: 0..0 }.choose(r), None);
+ }
+
+ #[test]
+ #[cfg_attr(miri, ignore)] // Miri is too slow
+ fn test_iterator_choose_stable_stability() {
+ fn test_iter(iter: impl Iterator<Item = usize> + Clone) -> [i32; 9] {
+ let r = &mut crate::test::rng(109);
+ let mut chosen = [0i32; 9];
+ for _ in 0..1000 {
+ let picked = iter.clone().choose_stable(r).unwrap();
+ chosen[picked] += 1;
+ }
+ chosen
+ }
+
+ let reference = test_iter(0..9);
+ assert_eq!(test_iter([0, 1, 2, 3, 4, 5, 6, 7, 8].iter().cloned()), reference);
+
+ #[cfg(feature = "alloc")]
+ assert_eq!(test_iter((0..9).collect::<Vec<_>>().into_iter()), reference);
+ assert_eq!(test_iter(UnhintedIterator { iter: 0..9 }), reference);
+ assert_eq!(test_iter(ChunkHintedIterator {
+ iter: 0..9,
+ chunk_size: 4,
+ chunk_remaining: 4,
+ hint_total_size: false,
+ }), reference);
+ assert_eq!(test_iter(ChunkHintedIterator {
+ iter: 0..9,
+ chunk_size: 4,
+ chunk_remaining: 4,
+ hint_total_size: true,
+ }), reference);
+ assert_eq!(test_iter(WindowHintedIterator {
+ iter: 0..9,
+ window_size: 2,
+ hint_total_size: false,
+ }), reference);
+ assert_eq!(test_iter(WindowHintedIterator {
+ iter: 0..9,
+ window_size: 2,
+ hint_total_size: true,
+ }), reference);
+ }
+
+ #[test]
+ #[cfg_attr(miri, ignore)] // Miri is too slow
fn test_shuffle() {
let mut r = crate::test::rng(108);
let empty: &mut [isize] = &mut [];
@@ -847,4 +1108,248 @@
Err(WeightedError::InvalidWeight)
);
}
+
+ #[test]
+ fn value_stability_choose() {
+ fn choose<I: Iterator<Item = u32>>(iter: I) -> Option<u32> {
+ let mut rng = crate::test::rng(411);
+ iter.choose(&mut rng)
+ }
+
+ assert_eq!(choose([].iter().cloned()), None);
+ assert_eq!(choose(0..100), Some(33));
+ assert_eq!(choose(UnhintedIterator { iter: 0..100 }), Some(40));
+ assert_eq!(
+ choose(ChunkHintedIterator {
+ iter: 0..100,
+ chunk_size: 32,
+ chunk_remaining: 32,
+ hint_total_size: false,
+ }),
+ Some(39)
+ );
+ assert_eq!(
+ choose(ChunkHintedIterator {
+ iter: 0..100,
+ chunk_size: 32,
+ chunk_remaining: 32,
+ hint_total_size: true,
+ }),
+ Some(39)
+ );
+ assert_eq!(
+ choose(WindowHintedIterator {
+ iter: 0..100,
+ window_size: 32,
+ hint_total_size: false,
+ }),
+ Some(90)
+ );
+ assert_eq!(
+ choose(WindowHintedIterator {
+ iter: 0..100,
+ window_size: 32,
+ hint_total_size: true,
+ }),
+ Some(90)
+ );
+ }
+
+ #[test]
+ fn value_stability_choose_stable() {
+ fn choose<I: Iterator<Item = u32>>(iter: I) -> Option<u32> {
+ let mut rng = crate::test::rng(411);
+ iter.choose_stable(&mut rng)
+ }
+
+ assert_eq!(choose([].iter().cloned()), None);
+ assert_eq!(choose(0..100), Some(40));
+ assert_eq!(choose(UnhintedIterator { iter: 0..100 }), Some(40));
+ assert_eq!(
+ choose(ChunkHintedIterator {
+ iter: 0..100,
+ chunk_size: 32,
+ chunk_remaining: 32,
+ hint_total_size: false,
+ }),
+ Some(40)
+ );
+ assert_eq!(
+ choose(ChunkHintedIterator {
+ iter: 0..100,
+ chunk_size: 32,
+ chunk_remaining: 32,
+ hint_total_size: true,
+ }),
+ Some(40)
+ );
+ assert_eq!(
+ choose(WindowHintedIterator {
+ iter: 0..100,
+ window_size: 32,
+ hint_total_size: false,
+ }),
+ Some(40)
+ );
+ assert_eq!(
+ choose(WindowHintedIterator {
+ iter: 0..100,
+ window_size: 32,
+ hint_total_size: true,
+ }),
+ Some(40)
+ );
+ }
+
+ #[test]
+ fn value_stability_choose_multiple() {
+ fn do_test<I: Iterator<Item = u32>>(iter: I, v: &[u32]) {
+ let mut rng = crate::test::rng(412);
+ let mut buf = [0u32; 8];
+ assert_eq!(iter.choose_multiple_fill(&mut rng, &mut buf), v.len());
+ assert_eq!(&buf[0..v.len()], v);
+ }
+
+ do_test(0..4, &[0, 1, 2, 3]);
+ do_test(0..8, &[0, 1, 2, 3, 4, 5, 6, 7]);
+ do_test(0..100, &[58, 78, 80, 92, 43, 8, 96, 7]);
+
+ #[cfg(feature = "alloc")]
+ {
+ fn do_test<I: Iterator<Item = u32>>(iter: I, v: &[u32]) {
+ let mut rng = crate::test::rng(412);
+ assert_eq!(iter.choose_multiple(&mut rng, v.len()), v);
+ }
+
+ do_test(0..4, &[0, 1, 2, 3]);
+ do_test(0..8, &[0, 1, 2, 3, 4, 5, 6, 7]);
+ do_test(0..100, &[58, 78, 80, 92, 43, 8, 96, 7]);
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ fn test_multiple_weighted_edge_cases() {
+ use super::*;
+
+ let mut rng = crate::test::rng(413);
+
+ // Case 1: One of the weights is 0
+ let choices = [('a', 2), ('b', 1), ('c', 0)];
+ for _ in 0..100 {
+ let result = choices
+ .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+ .unwrap()
+ .collect::<Vec<_>>();
+
+ assert_eq!(result.len(), 2);
+ assert!(!result.iter().any(|val| val.0 == 'c'));
+ }
+
+ // Case 2: All of the weights are 0
+ let choices = [('a', 0), ('b', 0), ('c', 0)];
+ let result = choices
+ .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+ .unwrap()
+ .collect::<Vec<_>>();
+ assert_eq!(result.len(), 2);
+
+ // Case 3: Negative weights
+ let choices = [('a', -1), ('b', 1), ('c', 1)];
+ assert_eq!(
+ choices
+ .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+ .unwrap_err(),
+ WeightedError::InvalidWeight
+ );
+
+ // Case 4: Empty list
+ let choices = [];
+ let result = choices
+ .choose_multiple_weighted(&mut rng, 0, |_: &()| 0)
+ .unwrap()
+ .collect::<Vec<_>>();
+ assert_eq!(result.len(), 0);
+
+ // Case 5: NaN weights
+ let choices = [('a', core::f64::NAN), ('b', 1.0), ('c', 1.0)];
+ assert_eq!(
+ choices
+ .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+ .unwrap_err(),
+ WeightedError::InvalidWeight
+ );
+
+ // Case 6: +infinity weights
+ let choices = [('a', core::f64::INFINITY), ('b', 1.0), ('c', 1.0)];
+ for _ in 0..100 {
+ let result = choices
+ .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+ .unwrap()
+ .collect::<Vec<_>>();
+ assert_eq!(result.len(), 2);
+ assert!(result.iter().any(|val| val.0 == 'a'));
+ }
+
+ // Case 7: -infinity weights
+ let choices = [('a', core::f64::NEG_INFINITY), ('b', 1.0), ('c', 1.0)];
+ assert_eq!(
+ choices
+ .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+ .unwrap_err(),
+ WeightedError::InvalidWeight
+ );
+
+ // Case 8: -0 weights
+ let choices = [('a', -0.0), ('b', 1.0), ('c', 1.0)];
+ assert!(choices
+ .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+ .is_ok());
+ }
+
+ #[test]
+ #[cfg(feature = "alloc")]
+ fn test_multiple_weighted_distributions() {
+ use super::*;
+
+ // The theoretical probabilities of the different outcomes are:
+ // AB: 0.5 * 0.5 = 0.250
+ // AC: 0.5 * 0.5 = 0.250
+ // BA: 0.25 * 0.67 = 0.167
+ // BC: 0.25 * 0.33 = 0.082
+ // CA: 0.25 * 0.67 = 0.167
+ // CB: 0.25 * 0.33 = 0.082
+ let choices = [('a', 2), ('b', 1), ('c', 1)];
+ let mut rng = crate::test::rng(414);
+
+ let mut results = [0i32; 3];
+ let expected_results = [4167, 4167, 1666];
+ for _ in 0..10000 {
+ let result = choices
+ .choose_multiple_weighted(&mut rng, 2, |item| item.1)
+ .unwrap()
+ .collect::<Vec<_>>();
+
+ assert_eq!(result.len(), 2);
+
+ match (result[0].0, result[1].0) {
+ ('a', 'b') | ('b', 'a') => {
+ results[0] += 1;
+ }
+ ('a', 'c') | ('c', 'a') => {
+ results[1] += 1;
+ }
+ ('b', 'c') | ('c', 'b') => {
+ results[2] += 1;
+ }
+ (_, _) => panic!("unexpected result"),
+ }
+ }
+
+ let mut diffs = results
+ .iter()
+ .zip(&expected_results)
+ .map(|(a, b)| (a - b).abs());
+ assert!(!diffs.any(|deviation| deviation > 100));
+ }
}