зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1716518 - Upgrade rand to v0.7.3 and rand_chacha to v0.2.2. r=emilio
This removes c2-chacha. Differential Revision: https://phabricator.services.mozilla.com/D117841
This commit is contained in:
Родитель
7fda4d5401
Коммит
aed4dbceb0
|
@ -468,15 +468,6 @@ version = "0.5.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
|
||||
|
||||
[[package]]
|
||||
name = "c2-chacha"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cache-padded"
|
||||
version = "1.1.1"
|
||||
|
@ -4035,9 +4026,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libc",
|
||||
|
@ -4049,11 +4040,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"c2-chacha",
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{"files":{"Cargo.toml":"ca60f483e157aa3a4da8f2e81328a91085df95aac950af29b98ba00264670118","LICENSE-APACHE":"0218327e7a480793ffdd4eb792379a9709e5c135c7ba267f709d6f6d4d70af0a","LICENSE-MIT":"4cada0bd02ea3692eee6f16400d86c6508bbd3bafb2b65fed0419f36d4f83e8f","README.md":"e884c49fd9cf2d6316cb825e1cfc310ed8d9005ecf702506393f95330102a63b","benches/chacha20.rs":"e499e9d8607ad6ac89663258fb8ce4d37cebb5cd231bc8d9c1112fb7905eccb6","src/guts.rs":"ef6337688f5a3d5cbd848e882b53ef2b96824126783103c77709c5dd2856b660","src/lib.rs":"f963f2932409ff28a21a89d5dc4f44c1a9b320705cc474246a93067abcf4b528","src/rustcrypto_impl.rs":"805692d33643b40430559710184e52ac49c82d41a23e6c112e19251e2ea84656"},"package":"214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"}
|
|
@ -1,46 +0,0 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "c2-chacha"
|
||||
version = "0.2.3"
|
||||
authors = ["The CryptoCorrosion Contributors"]
|
||||
description = "The ChaCha family of stream ciphers"
|
||||
documentation = "https://docs.rs/c2-chacha"
|
||||
readme = "README.md"
|
||||
keywords = ["chacha", "chacha20", "xchacha20", "cipher", "crypto"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/cryptocorrosion/cryptocorrosion"
|
||||
[dependencies.byteorder]
|
||||
version = "1.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.ppv-lite86]
|
||||
version = "0.2.6"
|
||||
default-features = false
|
||||
package = "ppv-lite86"
|
||||
|
||||
[dependencies.stream-cipher]
|
||||
version = "0.3"
|
||||
optional = true
|
||||
[dev-dependencies.hex-literal]
|
||||
version = "0.2"
|
||||
|
||||
[features]
|
||||
default = ["std", "simd", "rustcrypto_api"]
|
||||
rustcrypto_api = ["stream-cipher", "byteorder"]
|
||||
simd = ["ppv-lite86/simd"]
|
||||
std = ["ppv-lite86/std"]
|
||||
[badges.travis-ci]
|
||||
repository = "cryptocorrosion/cryptocorrosion"
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 The CryptoCorrosion Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2019 The CryptoCorrosion Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
|
@ -1,24 +0,0 @@
|
|||
# The ChaCha family of stream ciphers
|
||||
|
||||
## Features
|
||||
|
||||
- pure Rust implementation
|
||||
- supports the RustCrypto API
|
||||
- builds on stable Rust
|
||||
- portable
|
||||
- fast: within 15% of throughput of a hand-optimized ASM SIMD implementation
|
||||
(floodberry/chacha-opt) on my machine (a Xeon X5650, using ppv-lite86)
|
||||
- no-std compatible (std required only for runtime algorithm selection)
|
||||
|
||||
## Supported Variants
|
||||
|
||||
ChaCha20: used in chacha20-poly1305 in TLS, OpenSSH; arc4random in the BSDs,
|
||||
Linux /dev/urandom since 4.8.
|
||||
|
||||
Ietf: IETF RFC 7539. Longer nonce, short block counter.
|
||||
|
||||
XChaCha20: constructed analogously to XSalsa20; a mixing step during
|
||||
initialization allows using a long nonce and along with a full-sized block
|
||||
counter.
|
||||
|
||||
ChaCha12, ChaCha8: faster; lower security margin of safety.
|
|
@ -1,20 +0,0 @@
|
|||
#![feature(test)]
|
||||
extern crate c2_chacha;
|
||||
extern crate stream_cipher;
|
||||
extern crate test;
|
||||
|
||||
use c2_chacha::ChaCha20;
|
||||
use stream_cipher::{NewStreamCipher, SyncStreamCipher};
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
pub fn stream_10k(b: &mut Bencher) {
|
||||
let mut state = ChaCha20::new_var(&[0; 32], &[0; 8]).unwrap();
|
||||
let mut result = [0; 1024];
|
||||
b.iter(|| {
|
||||
for _ in 0..10 {
|
||||
state.apply_keystream(&mut result)
|
||||
}
|
||||
});
|
||||
b.bytes = 10240;
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
// copyright 2019 Kaz Wesley
|
||||
|
||||
//! Pure Rust ChaCha with SIMD optimizations.
|
||||
//!
|
||||
//! Stream-cipher usage:
|
||||
//! ```
|
||||
//! extern crate c2_chacha;
|
||||
//!
|
||||
//! use c2_chacha::stream_cipher::{NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek};
|
||||
//! use c2_chacha::{ChaCha20, ChaCha12};
|
||||
//!
|
||||
//! let key = b"very secret key-the most secret.";
|
||||
//! let iv = b"my nonce";
|
||||
//! let plaintext = b"The quick brown fox jumps over the lazy dog.";
|
||||
//!
|
||||
//! let mut buffer = plaintext.to_vec();
|
||||
//! // create cipher instance
|
||||
//! let mut cipher = ChaCha20::new_var(key, iv).unwrap();
|
||||
//! // apply keystream (encrypt)
|
||||
//! cipher.apply_keystream(&mut buffer);
|
||||
//! // and decrypt it back
|
||||
//! cipher.seek(0);
|
||||
//! cipher.apply_keystream(&mut buffer);
|
||||
//! // stream ciphers can be used with streaming messages
|
||||
//! let mut cipher = ChaCha12::new_var(key, iv).unwrap();
|
||||
//! for chunk in buffer.chunks_mut(3) {
|
||||
//! cipher.apply_keystream(chunk);
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate hex_literal;
|
||||
|
||||
#[macro_use]
|
||||
extern crate ppv_lite86;
|
||||
|
||||
pub mod guts;
|
||||
|
||||
#[cfg(feature = "rustcrypto_api")]
|
||||
mod rustcrypto_impl;
|
||||
#[cfg(feature = "rustcrypto_api")]
|
||||
pub use self::rustcrypto_impl::{stream_cipher, ChaCha12, ChaCha20, ChaCha8, Ietf, XChaCha20};
|
|
@ -1,548 +0,0 @@
|
|||
use byteorder::{ByteOrder, LE};
|
||||
use core::cmp;
|
||||
use crate::guts::generic_array::typenum::{Unsigned, U10, U12, U24, U32, U4, U6, U8};
|
||||
use crate::guts::generic_array::{ArrayLength, GenericArray};
|
||||
use crate::guts::{ChaCha, Machine, BLOCK, BLOCK64, BUFSZ};
|
||||
pub use stream_cipher;
|
||||
use stream_cipher::{LoopError, NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek};
|
||||
|
||||
const BIG_LEN: u64 = 0;
|
||||
const SMALL_LEN: u64 = 1 << 32;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Buffer {
|
||||
pub state: ChaCha,
|
||||
pub out: [u8; BLOCK],
|
||||
pub have: i8,
|
||||
pub len: u64,
|
||||
pub fresh: bool,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct X;
|
||||
#[derive(Default)]
|
||||
pub struct O;
|
||||
#[derive(Clone)]
|
||||
pub struct ChaChaAny<NonceSize, Rounds, IsX> {
|
||||
pub state: Buffer,
|
||||
pub _nonce_size: NonceSize,
|
||||
pub _rounds: Rounds,
|
||||
pub _is_x: IsX,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
fn try_apply_keystream<EnableWide: AsBool>(
|
||||
&mut self,
|
||||
mut data: &mut [u8],
|
||||
drounds: u32,
|
||||
) -> Result<(), ()> {
|
||||
// Lazy fill: after a seek() we may be partway into a block we don't have yet.
|
||||
// We can do this before the overflow check because this is not an effect of the current
|
||||
// operation.
|
||||
if self.have < 0 {
|
||||
self.state.refill(drounds, &mut self.out);
|
||||
self.have += BLOCK as i8;
|
||||
// checked in seek()
|
||||
self.len -= 1;
|
||||
}
|
||||
let mut have = self.have as usize;
|
||||
let have_ready = cmp::min(have, data.len());
|
||||
// Check if the requested position would wrap the block counter. Use self.fresh as an extra
|
||||
// bit to distinguish the initial state from the valid state with no blocks left.
|
||||
let datalen = (data.len() - have_ready) as u64;
|
||||
let blocks_needed = datalen / BLOCK64 + u64::from(datalen % BLOCK64 != 0);
|
||||
let (l, o) = self.len.overflowing_sub(blocks_needed);
|
||||
if o && !self.fresh {
|
||||
return Err(());
|
||||
}
|
||||
self.len = l;
|
||||
self.fresh &= blocks_needed == 0;
|
||||
// If we have data in the buffer, use that first.
|
||||
let (d0, d1) = data.split_at_mut(have_ready);
|
||||
for (data_b, key_b) in d0.iter_mut().zip(&self.out[(BLOCK - have)..]) {
|
||||
*data_b ^= *key_b;
|
||||
}
|
||||
data = d1;
|
||||
have -= have_ready;
|
||||
// Process wide chunks.
|
||||
if EnableWide::BOOL {
|
||||
let (d0, d1) = data.split_at_mut(data.len() & !(BUFSZ - 1));
|
||||
for dd in d0.chunks_exact_mut(BUFSZ) {
|
||||
let mut buf = [0; BUFSZ];
|
||||
self.state.refill4(drounds, &mut buf);
|
||||
for (data_b, key_b) in dd.iter_mut().zip(buf.iter()) {
|
||||
*data_b ^= *key_b;
|
||||
}
|
||||
}
|
||||
data = d1;
|
||||
}
|
||||
// Handle the tail a block at a time so we'll have storage for any leftovers.
|
||||
for dd in data.chunks_mut(BLOCK) {
|
||||
self.state.refill(drounds, &mut self.out);
|
||||
for (data_b, key_b) in dd.iter_mut().zip(self.out.iter()) {
|
||||
*data_b ^= *key_b;
|
||||
}
|
||||
have = BLOCK - dd.len();
|
||||
}
|
||||
self.have = have as i8;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_light128!(m, Mach, {
|
||||
fn seek64(buf: &mut Buffer, ct: u64) {
|
||||
let blockct = ct / BLOCK64;
|
||||
buf.len = BIG_LEN.wrapping_sub(blockct);
|
||||
buf.fresh = blockct == 0;
|
||||
buf.have = -((ct % BLOCK64) as i8);
|
||||
buf.state.seek64(m, blockct);
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_light128!(m, Mach, {
|
||||
fn seek32(buf: &mut Buffer, ct: u64) {
|
||||
let blockct = ct / BLOCK64;
|
||||
assert!(blockct < SMALL_LEN || (blockct == SMALL_LEN && ct % BLOCK64 == 0));
|
||||
buf.len = SMALL_LEN - blockct;
|
||||
buf.have = -((ct % BLOCK64) as i8);
|
||||
buf.state.seek32(m, blockct as u32);
|
||||
}
|
||||
});
|
||||
|
||||
#[cfg(test)]
|
||||
impl<NonceSize, Rounds: Unsigned, IsX> ChaChaAny<NonceSize, Rounds, IsX> {
|
||||
pub fn try_apply_keystream_narrow(&mut self, data: &mut [u8]) -> Result<(), ()> {
|
||||
self.state
|
||||
.try_apply_keystream::<WideDisabled>(data, Rounds::U32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<NonceSize, Rounds> ChaChaAny<NonceSize, Rounds, O>
|
||||
where
|
||||
NonceSize: Unsigned + ArrayLength<u8> + Default,
|
||||
Rounds: Default,
|
||||
{
|
||||
#[inline]
|
||||
fn new(key: &GenericArray<u8, U32>, nonce: &GenericArray<u8, NonceSize>) -> Self {
|
||||
let nonce_len = nonce.len();
|
||||
ChaChaAny {
|
||||
state: Buffer {
|
||||
state: init_chacha(key, nonce),
|
||||
out: [0; BLOCK],
|
||||
have: 0,
|
||||
len: if nonce_len == 12 { SMALL_LEN } else { BIG_LEN },
|
||||
fresh: nonce_len != 12,
|
||||
},
|
||||
_nonce_size: Default::default(),
|
||||
_rounds: Default::default(),
|
||||
_is_x: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rounds: Unsigned + Default> ChaChaAny<U24, Rounds, X> {
|
||||
fn new(key: &GenericArray<u8, U32>, nonce: &GenericArray<u8, U24>) -> Self {
|
||||
ChaChaAny {
|
||||
state: Buffer {
|
||||
state: init_chacha_x(key, nonce, Rounds::U32),
|
||||
out: [0; BLOCK],
|
||||
have: 0,
|
||||
len: BIG_LEN,
|
||||
fresh: true,
|
||||
},
|
||||
_nonce_size: Default::default(),
|
||||
_rounds: Default::default(),
|
||||
_is_x: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NonceSize: Unsigned, Rounds, IsX> ChaChaAny<NonceSize, Rounds, IsX> {
|
||||
#[inline(always)]
|
||||
fn seek(&mut self, ct: u64) {
|
||||
if NonceSize::U32 != 12 {
|
||||
seek64(&mut self.state, ct);
|
||||
} else {
|
||||
seek32(&mut self.state, ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<NonceSize, Rounds: Unsigned, IsX> ChaChaAny<NonceSize, Rounds, IsX> {
|
||||
#[inline]
|
||||
fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), ()> {
|
||||
self.state
|
||||
.try_apply_keystream::<WideEnabled>(data, Rounds::U32)
|
||||
}
|
||||
}
|
||||
|
||||
impl<NonceSize, Rounds> NewStreamCipher for ChaChaAny<NonceSize, Rounds, O>
|
||||
where
|
||||
NonceSize: Unsigned + ArrayLength<u8> + Default,
|
||||
Rounds: Default,
|
||||
{
|
||||
type KeySize = U32;
|
||||
type NonceSize = NonceSize;
|
||||
#[inline]
|
||||
fn new(
|
||||
key: &GenericArray<u8, Self::KeySize>,
|
||||
nonce: &GenericArray<u8, Self::NonceSize>,
|
||||
) -> Self {
|
||||
Self::new(key, nonce)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Rounds: Unsigned + Default> NewStreamCipher for ChaChaAny<U24, Rounds, X> {
|
||||
type KeySize = U32;
|
||||
type NonceSize = U24;
|
||||
#[inline]
|
||||
fn new(
|
||||
key: &GenericArray<u8, Self::KeySize>,
|
||||
nonce: &GenericArray<u8, Self::NonceSize>,
|
||||
) -> Self {
|
||||
Self::new(key, nonce)
|
||||
}
|
||||
}
|
||||
|
||||
impl<NonceSize: Unsigned, Rounds, IsX> SyncStreamCipherSeek for ChaChaAny<NonceSize, Rounds, IsX> {
|
||||
#[inline]
|
||||
fn current_pos(&self) -> u64 {
|
||||
unimplemented!()
|
||||
}
|
||||
#[inline(always)]
|
||||
fn seek(&mut self, ct: u64) {
|
||||
Self::seek(self, ct)
|
||||
}
|
||||
}
|
||||
|
||||
impl<NonceSize, Rounds: Unsigned, IsX> SyncStreamCipher for ChaChaAny<NonceSize, Rounds, IsX> {
|
||||
#[inline]
|
||||
fn try_apply_keystream(&mut self, data: &mut [u8]) -> Result<(), LoopError> {
|
||||
Self::try_apply_keystream(self, data).map_err(|_| LoopError)
|
||||
}
|
||||
}
|
||||
|
||||
trait AsBool {
|
||||
const BOOL: bool;
|
||||
}
|
||||
struct WideEnabled;
|
||||
impl AsBool for WideEnabled {
|
||||
const BOOL: bool = true;
|
||||
}
|
||||
#[cfg(test)]
|
||||
struct WideDisabled;
|
||||
#[cfg(test)]
|
||||
impl AsBool for WideDisabled {
|
||||
const BOOL: bool = false;
|
||||
}
|
||||
|
||||
dispatch_light128!(m, Mach, {
|
||||
fn init_chacha(key: &GenericArray<u8, U32>, nonce: &[u8]) -> ChaCha {
|
||||
let ctr_nonce = [
|
||||
0,
|
||||
if nonce.len() == 12 {
|
||||
LE::read_u32(&nonce[0..4])
|
||||
} else {
|
||||
0
|
||||
},
|
||||
LE::read_u32(&nonce[nonce.len() - 8..nonce.len() - 4]),
|
||||
LE::read_u32(&nonce[nonce.len() - 4..]),
|
||||
];
|
||||
let key0: Mach::u32x4 = m.read_le(&key[..16]);
|
||||
let key1: Mach::u32x4 = m.read_le(&key[16..]);
|
||||
ChaCha {
|
||||
b: key0.into(),
|
||||
c: key1.into(),
|
||||
d: ctr_nonce.into(),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dispatch_light128!(m, Mach, {
|
||||
fn init_chacha_x(
|
||||
key: &GenericArray<u8, U32>,
|
||||
nonce: &GenericArray<u8, U24>,
|
||||
rounds: u32,
|
||||
) -> ChaCha {
|
||||
let key0: Mach::u32x4 = m.read_le(&key[..16]);
|
||||
let key1: Mach::u32x4 = m.read_le(&key[16..]);
|
||||
let nonce0: Mach::u32x4 = m.read_le(&nonce[..16]);
|
||||
let mut state = ChaCha {
|
||||
b: key0.into(),
|
||||
c: key1.into(),
|
||||
d: nonce0.into(),
|
||||
};
|
||||
let x = state.refill_rounds(rounds);
|
||||
let ctr_nonce1 = [
|
||||
0,
|
||||
0,
|
||||
LE::read_u32(&nonce[16..20]),
|
||||
LE::read_u32(&nonce[20..24]),
|
||||
];
|
||||
state.b = x.a;
|
||||
state.c = x.d;
|
||||
state.d = ctr_nonce1.into();
|
||||
state
|
||||
}
|
||||
});
|
||||
|
||||
/// IETF RFC 7539 ChaCha. Unsuitable for messages longer than 256 GiB.
|
||||
pub type Ietf = ChaChaAny<U12, U10, O>;
|
||||
/// ChaCha20, as used in several standards; from Bernstein's original publication.
|
||||
pub type ChaCha20 = ChaChaAny<U8, U10, O>;
|
||||
/// Similar to ChaCha20, but with fewer rounds for higher performance.
|
||||
pub type ChaCha12 = ChaChaAny<U8, U6, O>;
|
||||
/// Similar to ChaCha20, but with fewer rounds for higher performance.
|
||||
pub type ChaCha8 = ChaChaAny<U8, U4, O>;
|
||||
/// Constructed analogously to XSalsa20; mixes during initialization to support both a long nonce
|
||||
/// and a full-length (64-bit) block counter.
|
||||
pub type XChaCha20 = ChaChaAny<U24, U10, X>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn chacha20_case_1() {
|
||||
let key = hex!("fa44478c59ca70538e3549096ce8b523232c50d9e8e8d10c203ef6c8d07098a5");
|
||||
let nonce = hex!("8d3a0d6d7827c007");
|
||||
let expected = hex!("
|
||||
1546a547ff77c5c964e44fd039e913c6395c8f19d43efaa880750f6687b4e6e2d8f42f63546da2d133b5aa2f1ef3f218b6c72943089e4012
|
||||
210c2cbed0e8e93498a6825fc8ff7a504f26db33b6cbe36299436244c9b2eff88302c55933911b7d5dea75f2b6d4761ba44bb6f814c9879d
|
||||
2ba2ac8b178fa1104a368694872339738ffb960e33db39efb8eaef885b910eea078e7a1feb3f8185dafd1455b704d76da3a0ce4760741841
|
||||
217bba1e4ece760eaf68617133431feb806c061173af6b8b2a23be90c5d145cc258e3c119aab2800f0c7bc1959dae75481712cab731b7dfd
|
||||
783fa3a228f9968aaea68f36a92f43c9b523337a55b97bcaf5f5774447bf41e8");
|
||||
let mut state = ChaCha20::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
let offset = 0x3fffffff70u64;
|
||||
assert!((offset >> 38) != ((offset + 240) >> 38)); // This will overflow the small word of the counter
|
||||
state.seek(offset);
|
||||
let mut result = [0; 256];
|
||||
state.apply_keystream(&mut result);
|
||||
assert_eq!(&expected[..], &result[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chacha12_case_1() {
|
||||
let key = hex!("27fc120b013b829f1faeefd1ab417e8662f43e0d73f98de866e346353180fdb7");
|
||||
let nonce = hex!("db4b4a41d8df18aa");
|
||||
let expected = hex!("
|
||||
5f3c8c190a78ab7fe808cae9cbcb0a9837c893492d963a1c2eda6c1558b02c83fc02a44cbbb7e6204d51d1c2430e9c0b58f2937bf593840c
|
||||
850bda9051a1f051ddf09d2a03ebf09f01bdba9da0b6da791b2e645641047d11ebf85087d4de5c015fddd044");
|
||||
let mut state = ChaCha12::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
let mut result = [0u8; 100];
|
||||
state.apply_keystream(&mut result);
|
||||
assert_eq!(&expected[..], &result[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn chacha8_case_1() {
|
||||
let key = hex!("641aeaeb08036b617a42cf14e8c5d2d115f8d7cb6ea5e28b9bfaf83e038426a7");
|
||||
let nonce = hex!("a14a1168271d459b");
|
||||
let mut state = ChaCha8::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
let expected = hex!(
|
||||
"1721c044a8a6453522dddb3143d0be3512633ca3c79bf8ccc3594cb2c2f310f7bd544f55ce0db38123412d6c45207d5cf9af0c6c680cce1f
|
||||
7e43388d1b0346b7133c59fd6af4a5a568aa334ccdc38af5ace201df84d0a3ca225494ca6209345fcf30132e");
|
||||
let mut result = [0u8; 100];
|
||||
state.apply_keystream(&mut result);
|
||||
assert_eq!(&expected[..], &result[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ietf() {
|
||||
let key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
|
||||
let nonce = hex!("000000090000004a00000000");
|
||||
let expected = hex!(
|
||||
"
|
||||
10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4e
|
||||
d2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
|
||||
);
|
||||
let mut state = Ietf::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
let mut result = [0; 64];
|
||||
state.seek(64);
|
||||
state.apply_keystream(&mut result);
|
||||
assert_eq!(&expected[..], &result[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rfc_7539_case_1() {
|
||||
let key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
|
||||
let nonce = hex!("000000090000004a00000000");
|
||||
let mut state = Ietf::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
let mut result = [0; 128];
|
||||
state.apply_keystream(&mut result);
|
||||
let expected = hex!(
|
||||
"10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4e
|
||||
d2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
|
||||
);
|
||||
assert_eq!(&expected[..], &result[64..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rfc_7539_case_2() {
|
||||
let key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
|
||||
let nonce = hex!("000000000000004a00000000");
|
||||
let mut state = Ietf::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
let plaintext = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
|
||||
let mut buf = [0u8; 178];
|
||||
buf[64..].copy_from_slice(plaintext);
|
||||
state.apply_keystream(&mut buf);
|
||||
let expected = hex!("
|
||||
6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d624e65152ab
|
||||
8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74a35be6b40b8eedf2785e42
|
||||
874d");
|
||||
assert_eq!(&expected[..], &buf[64..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rfc_7539_case_2_chunked() {
|
||||
let key = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
|
||||
let nonce = hex!("000000000000004a00000000");
|
||||
let mut state = Ietf::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
let plaintext = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
|
||||
let mut buf = [0u8; 178];
|
||||
buf[64..].copy_from_slice(plaintext);
|
||||
state.apply_keystream(&mut buf[..40]);
|
||||
state.apply_keystream(&mut buf[40..78]);
|
||||
state.apply_keystream(&mut buf[78..79]);
|
||||
state.apply_keystream(&mut buf[79..128]);
|
||||
state.apply_keystream(&mut buf[128..]);
|
||||
let expected = hex!("
|
||||
6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f593dabcd62b3571639d624e65152ab
|
||||
8f530c359f0861d807ca0dbf500d6a6156a38e088a22b65e52bc514d16ccf806818ce91ab77937365af90bbf74a35be6b40b8eedf2785e42
|
||||
874d");
|
||||
assert_eq!(&expected[..], &buf[64..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xchacha20_case_1() {
|
||||
let key = hex!("82f411a074f656c66e7dbddb0a2c1b22760b9b2105f4ffdbb1d4b1e824e21def");
|
||||
let nonce = hex!("3b07ca6e729eb44a510b7a1be51847838a804f8b106b38bd");
|
||||
let mut state = XChaCha20::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
let mut xs = [0u8; 100];
|
||||
state.apply_keystream(&mut xs);
|
||||
let expected = hex!("
|
||||
201863970b8e081f4122addfdf32f6c03e48d9bc4e34a59654f49248b9be59d3eaa106ac3376e7e7d9d1251f2cbf61ef27000f3d19afb76b
|
||||
9c247151e7bc26467583f520518eccd2055ccd6cc8a195953d82a10c2065916778db35da2be44415d2f5efb0");
|
||||
assert_eq!(&expected[..], &xs[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_off_end() {
|
||||
let mut st = Ietf::new(
|
||||
GenericArray::from_slice(&[0xff; 32]),
|
||||
GenericArray::from_slice(&[0; 12]),
|
||||
);
|
||||
st.seek(0x40_0000_0000);
|
||||
|
||||
assert!(st.try_apply_keystream(&mut [0u8; 1]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_last_bytes() {
|
||||
let mut st = Ietf::new(
|
||||
GenericArray::from_slice(&[0xff; 32]),
|
||||
GenericArray::from_slice(&[0; 12]),
|
||||
);
|
||||
|
||||
st.seek(0x40_0000_0000 - 10);
|
||||
st.apply_keystream(&mut [0u8; 10]);
|
||||
assert!(st.try_apply_keystream(&mut [0u8; 1]).is_err());
|
||||
|
||||
st.seek(0x40_0000_0000 - 10);
|
||||
assert!(st.try_apply_keystream(&mut [0u8; 11]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seek_consistency() {
|
||||
let mut st = Ietf::new(
|
||||
GenericArray::from_slice(&[50; 32]),
|
||||
GenericArray::from_slice(&[44; 12]),
|
||||
);
|
||||
|
||||
let mut continuous = [0u8; 1000];
|
||||
st.apply_keystream(&mut continuous);
|
||||
|
||||
let mut chunks = [0u8; 1000];
|
||||
|
||||
st.seek(128);
|
||||
st.apply_keystream(&mut chunks[128..300]);
|
||||
|
||||
st.seek(0);
|
||||
st.apply_keystream(&mut chunks[0..10]);
|
||||
|
||||
st.seek(300);
|
||||
st.apply_keystream(&mut chunks[300..533]);
|
||||
|
||||
st.seek(533);
|
||||
st.apply_keystream(&mut chunks[533..]);
|
||||
|
||||
st.seek(10);
|
||||
st.apply_keystream(&mut chunks[10..128]);
|
||||
|
||||
assert_eq!(&continuous[..], &chunks[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wide_matches_narrow() {
|
||||
let key = hex!("fa44478c59ca70538e3549096ce8b523232c50d9e8e8d10c203ef6c8d07098a5");
|
||||
let nonce = hex!("8d3a0d6d7827c007");
|
||||
let mut buf = [0; 2048];
|
||||
let mut state = ChaCha20::new(
|
||||
GenericArray::from_slice(&key),
|
||||
GenericArray::from_slice(&nonce),
|
||||
);
|
||||
|
||||
let lens = [
|
||||
2048, 2047, 1537, 1536, 1535, 1025, 1024, 1023, 768, 513, 512, 511, 200, 100, 50,
|
||||
];
|
||||
|
||||
for &len in &lens {
|
||||
let buf = &mut buf[0..len];
|
||||
|
||||
// encrypt with hybrid wide/narrow
|
||||
state.seek(0);
|
||||
state.apply_keystream(buf);
|
||||
state.seek(0);
|
||||
// decrypt with narrow only
|
||||
state.try_apply_keystream_narrow(buf).unwrap();
|
||||
for &byte in buf.iter() {
|
||||
assert_eq!(byte, 0);
|
||||
}
|
||||
|
||||
// encrypt with hybrid wide/narrow
|
||||
let offset = 0x3fffffff70u64;
|
||||
state.seek(offset);
|
||||
state.apply_keystream(buf);
|
||||
// decrypt with narrow only
|
||||
state.seek(offset);
|
||||
state.try_apply_keystream_narrow(buf).unwrap();
|
||||
for &byte in buf.iter() {
|
||||
assert_eq!(byte, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
{"files":{"CHANGELOG.md":"6b229076724946d94360b3f6d06b6b3e36426d8b684a6d3d6b23d0ce3eed5fe5","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.lock":"d50ba66a164f236b6f4efe4ab8f0cf6f31361618a364324104fa1c55483e0f59","Cargo.toml":"0e5d02de8aecef9090f78a7f81921a63c4261140a00e9154f5e6c51d58f3acf5","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"7739fbd8b2a916d9e18fea431ccf0e55fd128428d4b6c64849dbba60dfda8a01","benches/generators.rs":"f431e5c618b5d7ceedb4720d0b0f0d20b73a4f895129e01bc24a47461b158116","benches/misc.rs":"ef3180a16c469cfcda2cf5146d8ea0e77552316f9e0ad0de4690cf492d725dfe","benches/seq.rs":"dea8cfb68e944acdd488fe464fbb68298f07bb972f55d0a963c775b5b253eb57","benches/weighted.rs":"67a40f456c7b024000c2db24f64af7ae24a147d3c2c55af1349970de3faca3fd","examples/monte-carlo.rs":"5c01a47885a31445e78fab076f8328a7732bca41d84e0d4ba5670b80ca7a883f","examples/monty-hall.rs":"437d5150e8375f64e24d6bac63b5385114196698d5457c8a1b4f50defa427a37","rustfmt.toml":"f0f95df871dbc3b5e6619a6a652746ff50d6185e4d5198fc9b70de703047c660","src/distributions/bernoulli.rs":"b711106b20af024378669991fd228e60ad3e402792fa8541fd7a82e030a42d19","src/distributions/binomial.rs":"0fc44a6ceb3440e706c52d38631f741c00b1b03165cf1f1acd4adfb89a6c998a","src/distributions/cauchy.rs":"c58768bf151786ff08148fe06024f9db05e450a4e24ffb50a94d8399f67b817b","src/distributions/dirichlet.rs":"bc3fa16b5d5c8ae472924f142efe1de06980ba31f73378750958348eba546390","src/distributions/exponential.rs":"02afd305a813bd6dd7d6f9148fd3284bb85e8aa07a9ba2b18e16ad66c2ca0cde","src/distributions/float.rs":"550e5bde1857bdfdb30bf4588384bb208f2092e2e89fc4f6d6cc7cf5dbdd4e1c","src/distributions/gamma.rs":"7853b91e322ad6dda2ecc944e5291e46524c32955d8e93d15eb22e68ecbadf55","src/distributions/integer.rs":"2f03db82cd3e9283c85d39b04e9437d9ba3e7b33a140f48d9b117a60876e4eb0","src/distributions/mod.rs":"a12883606bbb7b0be3c579d5fc25049223d30051a3362fd28072545bc43c0541","src/distributions/normal.rs":"afd5dfafc1ab4c6905ff823e5ece0a808731108c67bd9f7435454e1962018bba","src/distributions/other.rs":"8d198bc0c36775dea3bed1150746e868683b8504de763b678b49adf34bd68fdb","src/distributions/pareto.rs":"3d8f9467daa0c6a831da90e14cf2600352da32a37c5483858ae718f4c888c936","src/distributions/poisson.rs":"b6d848616f07cc6387a69fe1e8fcb7718fc25e7c7c5db27fb7356e29446346f1","src/distributions/triangular.rs":"0b1584f874eeef21b55189c072e3ba6003014a9507f461a0ae0a3e9a95a6a536","src/distributions/uniform.rs":"87024d6b3fd6c5630015bc0dac72e663503170c5ed8adc1e02533ad250771e34","src/distributions/unit_circle.rs":"34f58c46f57c7995cd6b8fe32906cd529bfe7bc8e53963177b7a478745af0bc1","src/distributions/unit_sphere.rs":"4db4f3af623cf4e40e00bf00b4c3f549a5ff8bf0c31468a4c77838f9dee5587a","src/distributions/utils.rs":"1c91cac422c52050091ee73873e79fbcaa7a4d6c99cf7f198b8e7f9c1936c05a","src/distributions/weibull.rs":"403a5c9e5b82ac252e27fd5d295769c557bb41d817cc98a3cbd6910d6221d2de","src/distributions/weighted/alias_method.rs":"2040efd98389f3073dba9dcc9b3f5055814fb9cbdc61794ae8d396512d8b5647","src/distributions/weighted/mod.rs":"f66d0101d02df411430fef07e04ca55f450ff1dd2873eb7073b30a6733f66c78","src/distributions/ziggurat_tables.rs":"6368acec20801c703ae76dd1e08983793732c5ac221c491f85d719ef75448b6d","src/lib.rs":"c5fb3ed272ed93bd8d799c50e46f872158d1a05ded1c89406d51052cd9dca37c","src/prelude.rs":"331b6249754e89cf0c493e443b41455ffce4146c24de2bffdd596f355d86e5f8","src/rngs/adapter/mod.rs":"a625303a793b3f7ee2e25d210204493d1774e0cee8b39dc2cab0035e80c0ce24","src/rngs/adapter/read.rs":"35a1f2bbd29485d4130b1e4b75f9fe0e9a0ef7e779e4c77b0dbfd23900bfdb42","src/rngs/adapter/reseeding.rs":"c62b32e7d925cdfb5972672a493d6edd8f304403fb6f6d5c0fb063d77467917b","src/rngs/entropy.rs":"3bf02b8b1d1531608e8483c8723a96fd30204f84318880851d2c431eabc72439","src/rngs/mock.rs":"18fad8c5c0c4625b2941919b5be89ef77f2a7841261005320b8689c9b1e5a8e3","src/rngs/mod.rs":"0678444670a1d88fbee6b7fcc17f4a84a584998b3e6367c86379d212180b2383","src/rngs/small.rs":"7435781d3229d1e17dfc4e2db991067395250dca7e6af724db09f93c6f96e277","src/rngs/std.rs":"2765d7a1cf85556af12cf46e24986711ba52592d4b8b139f7164368f4886a53b","src/rngs/thread.rs":"fe575428f4a1c9eeddefacf305b85ce645fa0b5d8caa4d1e41f9bbb63cc3ac0c","src/seq/index.rs":"a13461729540080c19da0f8a4b36d844f4519524858adb05adfffe386d330064","src/seq/mod.rs":"caa14c4ca934ffbf3bdc1bc0862f96852a5af39ebd0bc1784aa52981d44e5404"},"package":"3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"}
|
||||
{"files":{"CHANGELOG.md":"28794454ddd6739a1c0cfc6df90a25af3a6a62827d7f7aaea3ee39440b9ab87b","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.lock":"ee32a72318ee8c6986509e36ae276406b622897cb82324c3f0e39551f0edc2cb","Cargo.toml":"4bc436e4b01131f4809c2d3dbdd3ede6987135d3fb53f718cd4a85cafa240224","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"cc7af91db7807de40503b3033ea596aeb78a89c0997894ffd0e56c2fb06eab36","SECURITY.md":"b1c8e24e88bd81bb65bad212b1176d18a73f5191ae650a75784954a74acc31d4","benches/generators.rs":"361886b55d31449e7a649518e5a751eff4494cad8f3e247aee741dddd82d99a4","benches/misc.rs":"6fa587fb3bab8502b7dd88805a4255c5fc6b42b8b3f5d8eb727af1b80b0ebe29","benches/seq.rs":"bdc6c92a8cedb5ff41ac028618053eaf5bf4c7be8b16c83c79e9467039381302","benches/weighted.rs":"3649964f75cd6cb4e50134fbb14e09fb995ca6667cb34f99d0bd27a9429de3ea","examples/monte-carlo.rs":"e55087f1e1f48d723ffc49fb107f5846c163a5e0c97206cd43a261cbdf6bb1b4","examples/monty-hall.rs":"c079293ec0633717b4d903c63f9db166c2a0fe6c8ba9a98f084fb4975fccbc07","rustfmt.toml":"a582a93dc6492d36daae52df7800e369887ba0984d68d98f70b99ca870fed268","src/distributions/bernoulli.rs":"fa81935ea2091d43d373bb7f2f579522a5beae33c9aa9598fe8490298753eba7","src/distributions/binomial.rs":"667f4f2cddb7994aa68926dbdda4482c24ce28f9d392d2a439a9eb675bfe04be","src/distributions/cauchy.rs":"bf55d4535960136351938a92254d4429689c20ebba051808c171f818adbb1191","src/distributions/dirichlet.rs":"ef28a435d9fa6b2f8d953613135cf1be7905f3909edd86b65be4e77685dd9c47","src/distributions/exponential.rs":"0419f25e369b66226ecaaf500395bf3b0decc5f90aedba1151553085774129bf","src/distributions/float.rs":"8dc11e2e4ae743e19e7799da02862480f4499789d8c58c47fbeca5f7930d7cb9","src/distributions/gamma.rs":"bfa848d6165e653d6e461e5b92f49bb119c6f9e259ffe7d7b8fbb34234d611d1","src/distributions/integer.rs":"3eb86fe2a1aca9125463cc581245b498d8c23c0f80422e5496582d2763e605fc","src/distributions/mod.rs":"d2a2b3e36f2f8bdeb93ffc1f3032175b6a062f485e6bf78502401aa854c4fb24","src/distributions/normal.rs":"2ef7e174877f7ccb7c4ff5cbce5dc24eaad0cc700fad33a6d3c20b52ed8f4bcb","src/distributions/other.rs":"e0a6f5e2d6699e460267f463c95797781daf347bff9192b7af7630a18885290c","src/distributions/pareto.rs":"2c1fee43a4b408e9da32abec384542a243b96c5303371a63d0fc2f1baaa02c64","src/distributions/poisson.rs":"ec123c26b0029cb96325e2551e6c82c9b7f7a41c933cc3f40f6f6f6ac7990cef","src/distributions/triangular.rs":"4be8ba5eccdda8ab90319325381ff6952caf59261b59a7a6f79f8867ac426249","src/distributions/uniform.rs":"5a1af322eb2b6cca701bd0a14247b4387e78686318fd01f3213d0f3252cbea18","src/distributions/unit_circle.rs":"36d8640cb8b26fcdb1b7d4d6c0b349316117f9300f480304c8a15d9d148f5937","src/distributions/unit_sphere.rs":"4ecc4260d4e4cc3ebea679a29d2ec343a54d56016c37b2632d78e888a92cb584","src/distributions/utils.rs":"6478e01b2bd0de99e917373f3c86db1142ea10c67488691cbc10af29891ac6dc","src/distributions/weibull.rs":"9b5acc5981a44309820d3a1fd3fff17984590aeebb41a1cdf5098890ad1dec04","src/distributions/weighted/alias_method.rs":"6172aad0d461f6816a944dec00aac09e943fd13123ec518184995658538de7ed","src/distributions/weighted/mod.rs":"54386cf92d39c69b38208bc9b0e2f74949512784a43684d63523bee03c1cc8bc","src/distributions/ziggurat_tables.rs":"2994bb821a60681e0d7a2bb45fcdcbea1040aa775c9aab2c80a7161d753d1ad0","src/lib.rs":"588e35ffc5c859b588d99de6d331251939440383b09da92b1017ddced19a3f41","src/prelude.rs":"cb49fcfc4f0d3b6eaa43c00a667dd3456e6a321e98eee17320ec4a703d6faf4b","src/rngs/adapter/mod.rs":"851918de58eda79c0cb3f2c0756fb756a7769f35115a77a5ae2025e05b4c1d93","src/rngs/adapter/read.rs":"c162cd131c9ed4868415360f627aba17046d4acdae6b7cdc9c75a41e60757caa","src/rngs/adapter/reseeding.rs":"93d2fbf62d1a5765437c4360b94a2df69921fb9cd5b704c4c2023f53eb15ee03","src/rngs/entropy.rs":"a7a07e1f23c45332994eb0b76d250f68a2394048ab6fe3c6691fef719e30fb42","src/rngs/mock.rs":"d1ac752afa589bc3925067f98fe6c13223bda6c3e22b85abe22e4cd60e22bf90","src/rngs/mod.rs":"9ae5e9aa965d3393ef90983ab85834599432c9fc2c1d40de1b9237ab3fc91eb1","src/rngs/small.rs":"8cc5d1ae357554181b4c5fa978e95b667147c251f8431881da66b97ff584224c","src/rngs/std.rs":"82117975ada00199c8ca3677fc4e00bb8b574c50cd321e04b37d0c7542fa0b30","src/rngs/thread.rs":"ccb98ead28d49f6e35d6e50150cbd89579409fcfd792565aceb03e716447de9b","src/seq/index.rs":"4f2566bd9c189fc68a68fc1ad913c6efe3d3ea0699b1b1e110df9d51725c5b3d","src/seq/mod.rs":"26707ad8595093746852799c1d2eee159b69044abfedfcbfe26263a25f8035fa"},"package":"6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"}
|
|
@ -8,6 +8,19 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).
|
|||
|
||||
You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.
|
||||
|
||||
## [0.7.3] - 2020-01-10
|
||||
### Fixes
|
||||
- The `Bernoulli` distribution constructors now reports an error on NaN and on
|
||||
`denominator == 0`. (#925)
|
||||
- Use `std::sync::Once` to register fork handler, avoiding possible atomicity violation (#928)
|
||||
- Fix documentation on the precision of generated floating-point values
|
||||
|
||||
### Changes
|
||||
- Unix: make libc dependency optional; only use fork protection with std feature (#928)
|
||||
|
||||
### Additions
|
||||
- Implement `std::error::Error` for `BernoulliError` (#919)
|
||||
|
||||
## [0.7.2] - 2019-09-16
|
||||
### Fixes
|
||||
- Fix dependency on `rand_core` 0.5.1 (#890)
|
||||
|
@ -16,6 +29,11 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
|
|||
- Unit tests for value stability of distributions added (#888)
|
||||
|
||||
## [0.7.1] - 2019-09-13
|
||||
### Yanked
|
||||
This release was yanked since it depends on `rand_core::OsRng` added in 0.5.1
|
||||
but specifies a dependency on version 0.5.0 (#890), causing a broken builds
|
||||
when updating from `rand 0.7.0` without also updating `rand_core`.
|
||||
|
||||
### Fixes
|
||||
- Fix `no_std` behaviour, appropriately enable c2-chacha's `std` feature (#844)
|
||||
- `alloc` feature in `no_std` is available since Rust 1.36 (#856)
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "base-x"
|
||||
version = "0.2.5"
|
||||
|
@ -116,7 +111,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
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)",
|
||||
|
@ -125,10 +120,7 @@ dependencies = [
|
|||
"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_isaac 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -156,34 +148,9 @@ dependencies = [
|
|||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_isaac"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_xoshiro"
|
||||
version = "0.4.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -377,7 +344,6 @@ version = "0.2.50"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
|
||||
"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"
|
||||
|
@ -397,10 +363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"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_isaac 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8df6b0b3dc9991a10b2d91a86d1129314502169a1bf6afa67328945e02498b76"
|
||||
"checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6"
|
||||
"checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
|
||||
"checksum rand_xoshiro 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
|
||||
"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"
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "rand"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
authors = ["The Rand Project Developers", "The Rust Project Developers"]
|
||||
exclude = ["/utils/*", "/.travis.yml", "/appveyor.yml", ".gitignore"]
|
||||
autobenches = true
|
||||
|
@ -50,18 +50,9 @@ optional = true
|
|||
[dev-dependencies.rand_hc]
|
||||
version = "0.2"
|
||||
|
||||
[dev-dependencies.rand_isaac]
|
||||
version = "0.2"
|
||||
|
||||
[dev-dependencies.rand_pcg]
|
||||
version = "0.2"
|
||||
|
||||
[dev-dependencies.rand_xorshift]
|
||||
version = "0.2"
|
||||
|
||||
[dev-dependencies.rand_xoshiro]
|
||||
version = "0.4"
|
||||
|
||||
[features]
|
||||
alloc = ["rand_core/alloc"]
|
||||
default = ["std"]
|
||||
|
@ -70,7 +61,7 @@ nightly = ["simd_support"]
|
|||
serde1 = []
|
||||
simd_support = ["packed_simd"]
|
||||
small_rng = ["rand_pcg"]
|
||||
std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom"]
|
||||
std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"]
|
||||
stdweb = ["getrandom_package/stdweb"]
|
||||
wasm-bindgen = ["getrandom_package/wasm-bindgen"]
|
||||
[target."cfg(not(target_os = \"emscripten\"))".dependencies.rand_chacha]
|
||||
|
@ -80,6 +71,7 @@ default-features = false
|
|||
version = "0.2"
|
||||
[target."cfg(unix)".dependencies.libc]
|
||||
version = "0.2.22"
|
||||
optional = true
|
||||
default-features = false
|
||||
[badges.appveyor]
|
||||
repository = "rust-random/rand"
|
||||
|
|
|
@ -67,6 +67,12 @@ 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,
|
||||
the crate's CHANGELOG *should* be updated with a rationale, and a search on the
|
||||
issue tracker with the keyword `yank` *should* uncover the motivation.
|
||||
|
||||
### Rust version requirements
|
||||
|
||||
Since version 0.7, Rand requires **Rustc version 1.32 or greater**.
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
# 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).
|
|
@ -19,15 +19,10 @@ use test::{black_box, Bencher};
|
|||
|
||||
use rand::prelude::*;
|
||||
use rand::rngs::adapter::ReseedingRng;
|
||||
use rand::rngs::{OsRng, mock::StepRng};
|
||||
use rand_isaac::{IsaacRng, Isaac64Rng};
|
||||
use rand_chacha::{ChaCha20Core, ChaCha8Rng, ChaCha12Rng, ChaCha20Rng};
|
||||
use rand_hc::{Hc128Rng};
|
||||
use rand::rngs::{mock::StepRng, OsRng};
|
||||
use rand_chacha::{ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Rng};
|
||||
use rand_hc::Hc128Rng;
|
||||
use rand_pcg::{Pcg32, Pcg64, Pcg64Mcg};
|
||||
use rand_xorshift::XorShiftRng;
|
||||
use rand_xoshiro::{Xoshiro256StarStar, Xoshiro256Plus, Xoshiro128StarStar,
|
||||
Xoshiro128Plus, Xoroshiro128StarStar, Xoroshiro128Plus, SplitMix64,
|
||||
Xoroshiro64StarStar, Xoroshiro64Star};
|
||||
|
||||
macro_rules! gen_bytes {
|
||||
($fnn:ident, $gen:expr) => {
|
||||
|
@ -43,20 +38,10 @@ macro_rules! gen_bytes {
|
|||
});
|
||||
b.bytes = BYTES_LEN as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
gen_bytes!(gen_bytes_step, StepRng::new(0, 1));
|
||||
gen_bytes!(gen_bytes_xorshift, XorShiftRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoshiro256starstar, Xoshiro256StarStar::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoshiro256plus, Xoshiro256Plus::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoshiro128starstar, Xoshiro128StarStar::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoshiro128plus, Xoshiro128Plus::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoroshiro128starstar, Xoroshiro128StarStar::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoroshiro128plus, Xoroshiro128Plus::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoroshiro64starstar, Xoroshiro64StarStar::from_entropy());
|
||||
gen_bytes!(gen_bytes_xoroshiro64star, Xoroshiro64Star::from_entropy());
|
||||
gen_bytes!(gen_bytes_splitmix64, SplitMix64::from_entropy());
|
||||
gen_bytes!(gen_bytes_pcg32, Pcg32::from_entropy());
|
||||
gen_bytes!(gen_bytes_pcg64, Pcg64::from_entropy());
|
||||
gen_bytes!(gen_bytes_pcg64mcg, Pcg64Mcg::from_entropy());
|
||||
|
@ -64,10 +49,8 @@ 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_isaac, IsaacRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_isaac64, Isaac64Rng::from_entropy());
|
||||
gen_bytes!(gen_bytes_std, StdRng::from_entropy());
|
||||
#[cfg(feature="small_rng")]
|
||||
#[cfg(feature = "small_rng")]
|
||||
gen_bytes!(gen_bytes_small, SmallRng::from_entropy());
|
||||
gen_bytes!(gen_bytes_os, OsRng);
|
||||
|
||||
|
@ -85,20 +68,10 @@ macro_rules! gen_uint {
|
|||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
gen_uint!(gen_u32_step, u32, StepRng::new(0, 1));
|
||||
gen_uint!(gen_u32_xorshift, u32, XorShiftRng::from_entropy());
|
||||
gen_uint!(gen_u32_xoshiro256starstar, u32, Xoshiro256StarStar::from_entropy());
|
||||
gen_uint!(gen_u32_xoshiro256plus, u32, Xoshiro256Plus::from_entropy());
|
||||
gen_uint!(gen_u32_xoshiro128starstar, u32, Xoshiro128StarStar::from_entropy());
|
||||
gen_uint!(gen_u32_xoshiro128plus, u32, Xoshiro128Plus::from_entropy());
|
||||
gen_uint!(gen_u32_xoroshiro128starstar, u32, Xoroshiro128StarStar::from_entropy());
|
||||
gen_uint!(gen_u32_xoroshiro128plus, u32, Xoroshiro128Plus::from_entropy());
|
||||
gen_uint!(gen_u32_xoroshiro64starstar, u32, Xoroshiro64StarStar::from_entropy());
|
||||
gen_uint!(gen_u32_xoroshiro64star, u32, Xoroshiro64Star::from_entropy());
|
||||
gen_uint!(gen_u32_splitmix64, u32, SplitMix64::from_entropy());
|
||||
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());
|
||||
|
@ -106,24 +79,12 @@ 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_isaac, u32, IsaacRng::from_entropy());
|
||||
gen_uint!(gen_u32_isaac64, u32, Isaac64Rng::from_entropy());
|
||||
gen_uint!(gen_u32_std, u32, StdRng::from_entropy());
|
||||
#[cfg(feature="small_rng")]
|
||||
#[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_xorshift, u64, XorShiftRng::from_entropy());
|
||||
gen_uint!(gen_u64_xoshiro256starstar, u64, Xoshiro256StarStar::from_entropy());
|
||||
gen_uint!(gen_u64_xoshiro256plus, u64, Xoshiro256Plus::from_entropy());
|
||||
gen_uint!(gen_u64_xoshiro128starstar, u64, Xoshiro128StarStar::from_entropy());
|
||||
gen_uint!(gen_u64_xoshiro128plus, u64, Xoshiro128Plus::from_entropy());
|
||||
gen_uint!(gen_u64_xoroshiro128starstar, u64, Xoroshiro128StarStar::from_entropy());
|
||||
gen_uint!(gen_u64_xoroshiro128plus, u64, Xoroshiro128Plus::from_entropy());
|
||||
gen_uint!(gen_u64_xoroshiro64starstar, u64, Xoroshiro64StarStar::from_entropy());
|
||||
gen_uint!(gen_u64_xoroshiro64star, u64, Xoroshiro64Star::from_entropy());
|
||||
gen_uint!(gen_u64_splitmix64, u64, SplitMix64::from_entropy());
|
||||
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());
|
||||
|
@ -131,10 +92,8 @@ 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_isaac, u64, IsaacRng::from_entropy());
|
||||
gen_uint!(gen_u64_isaac64, u64, Isaac64Rng::from_entropy());
|
||||
gen_uint!(gen_u64_std, u64, StdRng::from_entropy());
|
||||
#[cfg(feature="small_rng")]
|
||||
#[cfg(feature = "small_rng")]
|
||||
gen_uint!(gen_u64_small, u64, SmallRng::from_entropy());
|
||||
gen_uint!(gen_u64_os, u64, OsRng);
|
||||
|
||||
|
@ -142,31 +101,19 @@ macro_rules! init_gen {
|
|||
($fnn:ident, $gen:ident) => {
|
||||
#[bench]
|
||||
fn $fnn(b: &mut Bencher) {
|
||||
let mut rng = XorShiftRng::from_entropy();
|
||||
let mut rng = Pcg32::from_entropy();
|
||||
b.iter(|| {
|
||||
let r2 = $gen::from_rng(&mut rng).unwrap();
|
||||
r2
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
init_gen!(init_xorshift, XorShiftRng);
|
||||
init_gen!(init_xoshiro256starstar, Xoshiro256StarStar);
|
||||
init_gen!(init_xoshiro256plus, Xoshiro256Plus);
|
||||
init_gen!(init_xoshiro128starstar, Xoshiro128StarStar);
|
||||
init_gen!(init_xoshiro128plus, Xoshiro128Plus);
|
||||
init_gen!(init_xoroshiro128starstar, Xoroshiro128StarStar);
|
||||
init_gen!(init_xoroshiro128plus, Xoroshiro128Plus);
|
||||
init_gen!(init_xoroshiro64starstar, Xoroshiro64StarStar);
|
||||
init_gen!(init_xoroshiro64star, Xoroshiro64Star);
|
||||
init_gen!(init_splitmix64, SplitMix64);
|
||||
init_gen!(init_pcg32, Pcg32);
|
||||
init_gen!(init_pcg64, Pcg64);
|
||||
init_gen!(init_pcg64mcg, Pcg64Mcg);
|
||||
init_gen!(init_hc128, Hc128Rng);
|
||||
init_gen!(init_isaac, IsaacRng);
|
||||
init_gen!(init_isaac64, Isaac64Rng);
|
||||
init_gen!(init_chacha, ChaCha20Rng);
|
||||
|
||||
const RESEEDING_BYTES_LEN: usize = 1024 * 1024;
|
||||
|
@ -176,9 +123,7 @@ 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 rng = ReseedingRng::new(ChaCha20Core::from_entropy(), $thresh * 1024, OsRng);
|
||||
let mut buf = [0u8; RESEEDING_BYTES_LEN];
|
||||
b.iter(|| {
|
||||
for _ in 0..RESEEDING_BENCH_N {
|
||||
|
@ -188,7 +133,7 @@ macro_rules! reseeding_bytes {
|
|||
});
|
||||
b.bytes = RESEEDING_BYTES_LEN as u64 * RESEEDING_BENCH_N;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
reseeding_bytes!(reseeding_chacha20_4k, 4);
|
||||
|
@ -213,7 +158,7 @@ macro_rules! threadrng_uint {
|
|||
});
|
||||
b.bytes = size_of::<$ty>() as u64 * RAND_BENCH_N;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
threadrng_uint!(thread_rng_u32, u32);
|
||||
|
|
|
@ -14,8 +14,8 @@ const RAND_BENCH_N: u64 = 1000;
|
|||
|
||||
use test::Bencher;
|
||||
|
||||
use rand::distributions::{Bernoulli, Distribution, Standard};
|
||||
use rand::prelude::*;
|
||||
use rand::distributions::{Distribution, Standard, Bernoulli};
|
||||
use rand_pcg::{Pcg32, Pcg64Mcg};
|
||||
|
||||
#[bench]
|
||||
|
|
|
@ -26,7 +26,7 @@ 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];
|
||||
let x: &mut [usize] = &mut [1; 100];
|
||||
b.iter(|| {
|
||||
x.shuffle(&mut rng);
|
||||
x[0]
|
||||
|
@ -36,7 +36,7 @@ fn seq_shuffle_100(b: &mut Bencher) {
|
|||
#[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];
|
||||
let x: &mut [usize] = &mut [1; 1000];
|
||||
for i in 0..1000 {
|
||||
x[i] = i;
|
||||
}
|
||||
|
@ -55,19 +55,18 @@ macro_rules! seq_slice_choose_multiple {
|
|||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
|
||||
let x : &[i32] = &[$amount; $length];
|
||||
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)) {
|
||||
for (slot, sample) in result.iter_mut().zip(x.choose_multiple(&mut rng, $amount)) {
|
||||
*slot = *sample;
|
||||
}
|
||||
result[$amount-1]
|
||||
result[$amount - 1]
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
seq_slice_choose_multiple!(seq_slice_choose_multiple_1_of_1000, 1, 1000);
|
||||
|
@ -78,7 +77,7 @@ 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];
|
||||
let x: &mut [usize] = &mut [1; 1000];
|
||||
for i in 0..1000 {
|
||||
x[i] = i;
|
||||
}
|
||||
|
@ -98,6 +97,7 @@ struct UnhintedIterator<I: Iterator + Clone> {
|
|||
}
|
||||
impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> {
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
@ -110,9 +110,11 @@ struct WindowHintedIterator<I: ExactSizeIterator + Iterator + Clone> {
|
|||
}
|
||||
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)
|
||||
}
|
||||
|
@ -121,38 +123,40 @@ impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<
|
|||
#[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];
|
||||
let x: &[usize] = &[1; 1000];
|
||||
b.iter(|| {
|
||||
UnhintedIterator { iter: x.iter() }.choose(&mut rng).unwrap()
|
||||
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];
|
||||
let x: &[usize] = &[1; 1000];
|
||||
b.iter(|| {
|
||||
WindowHintedIterator { iter: x.iter(), window_size: 7 }.choose(&mut rng)
|
||||
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)
|
||||
})
|
||||
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 x: &[usize] = &[1; 100];
|
||||
let mut buf = [0; 10];
|
||||
b.iter(|| {
|
||||
x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf)
|
||||
})
|
||||
b.iter(|| x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf))
|
||||
}
|
||||
|
||||
macro_rules! sample_indices {
|
||||
|
@ -160,11 +164,9 @@ macro_rules! sample_indices {
|
|||
#[bench]
|
||||
fn $name(b: &mut Bencher) {
|
||||
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
|
||||
b.iter(|| {
|
||||
index::$fn(&mut rng, $length, $amount)
|
||||
})
|
||||
b.iter(|| index::$fn(&mut rng, $length, $amount))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
sample_indices!(misc_sample_indices_1_of_1k, sample, 1, 1000);
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
extern crate test;
|
||||
|
||||
use test::Bencher;
|
||||
use rand::Rng;
|
||||
use rand::distributions::WeightedIndex;
|
||||
use rand::Rng;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn weighted_index_creation(b: &mut Bencher) {
|
||||
|
|
|
@ -38,11 +38,14 @@ fn main() {
|
|||
for _ in 0..total {
|
||||
let a = range.sample(&mut rng);
|
||||
let b = range.sample(&mut rng);
|
||||
if a*a + b*b <= 1.0 {
|
||||
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));
|
||||
println!(
|
||||
"π is approximately {}",
|
||||
4. * (in_circle as f64) / (total as f64)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,10 @@ fn simulate<R: Rng>(random_door: &Uniform<u32>, rng: &mut R) -> SimulationResult
|
|||
choice = switch_door(choice, open);
|
||||
}
|
||||
|
||||
SimulationResult { win: choice == car, switch }
|
||||
SimulationResult {
|
||||
win: choice == car,
|
||||
switch,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the door the game host opens given our choice and knowledge of
|
||||
|
@ -97,16 +100,24 @@ fn main() {
|
|||
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!(
|
||||
"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);
|
||||
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);
|
||||
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
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
# Comments:
|
||||
normalize_comments = true
|
||||
wrap_comments = false
|
||||
format_doc_comments = true
|
||||
comment_width = 90 # small excess is okay but prefer 80
|
||||
|
||||
# Arguments:
|
||||
use_small_heuristics = "max"
|
||||
fn_args_density = "compressed"
|
||||
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
|
||||
|
||||
|
@ -21,6 +22,7 @@ where_single_line = true
|
|||
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"
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
//! The Bernoulli distribution.
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::Distribution;
|
||||
use crate::Rng;
|
||||
use core::{fmt, u64};
|
||||
|
||||
/// The Bernoulli distribution.
|
||||
///
|
||||
|
@ -55,7 +56,7 @@ pub struct Bernoulli {
|
|||
// the RNG, and pay the performance price for all uses that *are* reasonable.
|
||||
// Luckily, if `new()` and `sample` are close, the compiler can optimize out the
|
||||
// extra check.
|
||||
const ALWAYS_TRUE: u64 = ::core::u64::MAX;
|
||||
const ALWAYS_TRUE: u64 = u64::MAX;
|
||||
|
||||
// This is just `2.0.powi(64)`, but written this way because it is not available
|
||||
// in `no_std` mode.
|
||||
|
@ -68,6 +69,17 @@ pub enum BernoulliError {
|
|||
InvalidProbability,
|
||||
}
|
||||
|
||||
impl fmt::Display for BernoulliError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
BernoulliError::InvalidProbability => "p is outside [0, 1] in Bernoulli distribution",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::error::Error for BernoulliError {}
|
||||
|
||||
impl Bernoulli {
|
||||
/// Construct a new `Bernoulli` with the given probability of success `p`.
|
||||
///
|
||||
|
@ -81,26 +93,32 @@ impl Bernoulli {
|
|||
/// 2<sup>-64</sup> in `[0, 1]` can be represented as a `f64`.)
|
||||
#[inline]
|
||||
pub fn new(p: f64) -> Result<Bernoulli, BernoulliError> {
|
||||
if p < 0.0 || p >= 1.0 {
|
||||
if p == 1.0 { return Ok(Bernoulli { p_int: ALWAYS_TRUE }) }
|
||||
if !(p >= 0.0 && p < 1.0) {
|
||||
if p == 1.0 {
|
||||
return Ok(Bernoulli { p_int: ALWAYS_TRUE });
|
||||
}
|
||||
return Err(BernoulliError::InvalidProbability);
|
||||
}
|
||||
Ok(Bernoulli { p_int: (p * SCALE) as u64 })
|
||||
Ok(Bernoulli {
|
||||
p_int: (p * SCALE) as u64,
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a new `Bernoulli` with the probability of success of
|
||||
/// `numerator`-in-`denominator`. I.e. `new_ratio(2, 3)` will return
|
||||
/// a `Bernoulli` with a 2-in-3 chance, or about 67%, of returning `true`.
|
||||
///
|
||||
/// If `numerator == denominator` then the returned `Bernoulli` will always
|
||||
/// return `true`. If `numerator == 0` it will always return `false`.
|
||||
/// For `numerator > denominator` and `denominator == 0`, this returns an
|
||||
/// error. Otherwise, for `numerator == denominator`, samples are always
|
||||
/// true; for `numerator == 0` samples are always false.
|
||||
#[inline]
|
||||
pub fn from_ratio(numerator: u32, denominator: u32) -> Result<Bernoulli, BernoulliError> {
|
||||
if numerator > denominator {
|
||||
if numerator > denominator || denominator == 0 {
|
||||
return Err(BernoulliError::InvalidProbability);
|
||||
}
|
||||
if numerator == denominator {
|
||||
return Ok(Bernoulli { p_int: ALWAYS_TRUE })
|
||||
return Ok(Bernoulli { p_int: ALWAYS_TRUE });
|
||||
}
|
||||
let p_int = ((f64::from(numerator) / f64::from(denominator)) * SCALE) as u64;
|
||||
Ok(Bernoulli { p_int })
|
||||
|
@ -111,7 +129,9 @@ impl Distribution<bool> for Bernoulli {
|
|||
#[inline]
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> bool {
|
||||
// Make sure to always return true for p = 1.0.
|
||||
if self.p_int == ALWAYS_TRUE { return true; }
|
||||
if self.p_int == ALWAYS_TRUE {
|
||||
return true;
|
||||
}
|
||||
let v: u64 = rng.gen();
|
||||
v < self.p_int
|
||||
}
|
||||
|
@ -119,9 +139,9 @@ impl Distribution<bool> for Bernoulli {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Rng;
|
||||
use crate::distributions::Distribution;
|
||||
use super::Bernoulli;
|
||||
use crate::distributions::Distribution;
|
||||
use crate::Rng;
|
||||
|
||||
#[test]
|
||||
fn test_trivial() {
|
||||
|
@ -137,7 +157,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_average() {
|
||||
const P: f64 = 0.3;
|
||||
const NUM: u32 = 3;
|
||||
|
@ -161,9 +181,9 @@ mod test {
|
|||
assert!((avg1 - P).abs() < 5e-3);
|
||||
|
||||
let avg2 = (sum2 as f64) / (N as f64);
|
||||
assert!((avg2 - (NUM as f64)/(DENOM as f64)).abs() < 5e-3);
|
||||
assert!((avg2 - (NUM as f64) / (DENOM as f64)).abs() < 5e-3);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
let mut rng = crate::test::rng(3);
|
||||
|
@ -172,6 +192,8 @@ mod test {
|
|||
for x in &mut buf {
|
||||
*x = rng.sample(&distr);
|
||||
}
|
||||
assert_eq!(buf, [true, false, false, true, false, false, true, true, true, true]);
|
||||
assert_eq!(buf, [
|
||||
true, false, false, true, false, false, true, true, true, true
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
#![allow(deprecated)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
use crate::Rng;
|
||||
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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Binomial {
|
||||
/// Number of trials.
|
||||
|
@ -58,11 +58,7 @@ impl Distribution<u64> for Binomial {
|
|||
// 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 p = if self.p <= 0.5 { self.p } else { 1.0 - self.p };
|
||||
|
||||
let result;
|
||||
let q = 1. - p;
|
||||
|
@ -79,8 +75,7 @@ impl Distribution<u64> for Binomial {
|
|||
// 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) {
|
||||
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;
|
||||
|
@ -212,8 +207,8 @@ impl Distribution<u64> for Binomial {
|
|||
// 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 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;
|
||||
|
@ -233,15 +228,19 @@ impl Distribution<u64> for Binomial {
|
|||
(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)
|
||||
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;
|
||||
}
|
||||
|
@ -263,9 +262,9 @@ impl Distribution<u64> for Binomial {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::Rng;
|
||||
use crate::distributions::Distribution;
|
||||
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);
|
||||
|
@ -274,21 +273,30 @@ mod test {
|
|||
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; }
|
||||
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);
|
||||
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);
|
||||
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(not(miri))] // Miri is too slow
|
||||
#[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);
|
||||
|
|
|
@ -11,19 +11,19 @@
|
|||
#![allow(deprecated)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
use crate::Rng;
|
||||
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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Cauchy {
|
||||
median: f64,
|
||||
scale: f64
|
||||
scale: f64,
|
||||
}
|
||||
|
||||
impl Cauchy {
|
||||
|
@ -32,10 +32,7 @@ impl Cauchy {
|
|||
/// 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
|
||||
}
|
||||
Cauchy { median, scale }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,8 +51,8 @@ impl Distribution<f64> for Cauchy {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::distributions::Distribution;
|
||||
use super::Cauchy;
|
||||
use crate::distributions::Distribution;
|
||||
|
||||
fn median(mut numbers: &mut [f64]) -> f64 {
|
||||
sort(&mut numbers);
|
||||
|
@ -68,7 +65,6 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri doesn't support transcendental functions
|
||||
fn test_cauchy_averages() {
|
||||
// NOTE: given that the variance and mean are undefined,
|
||||
// this test does not have any rigorous statistical meaning.
|
||||
|
|
|
@ -11,16 +11,16 @@
|
|||
#![allow(deprecated)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::Distribution;
|
||||
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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Dirichlet {
|
||||
/// Concentration parameters (alpha)
|
||||
|
@ -32,7 +32,6 @@ impl Dirichlet {
|
|||
///
|
||||
/// # Panics
|
||||
/// - if `alpha.len() < 2`
|
||||
///
|
||||
#[inline]
|
||||
pub fn new<V: Into<Vec<f64>>>(alpha: V) -> Dirichlet {
|
||||
let a = alpha.into();
|
||||
|
@ -49,7 +48,6 @@ impl Dirichlet {
|
|||
/// # Panics
|
||||
/// - if `alpha <= 0.0`
|
||||
/// - if `size < 2`
|
||||
///
|
||||
#[inline]
|
||||
pub fn new_with_param(alpha: f64, size: usize) -> Dirichlet {
|
||||
assert!(alpha > 0.0);
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
//! The exponential distribution.
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::{Rng};
|
||||
use crate::distributions::{ziggurat_tables, Distribution};
|
||||
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
|
||||
|
@ -28,7 +28,7 @@ use crate::distributions::utils::ziggurat;
|
|||
/// 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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Exp1;
|
||||
|
||||
|
@ -45,10 +45,14 @@ impl Distribution<f64> for Exp1 {
|
|||
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)
|
||||
ziggurat(
|
||||
rng,
|
||||
false,
|
||||
&ziggurat_tables::ZIG_EXP_X,
|
||||
&ziggurat_tables::ZIG_EXP_F,
|
||||
pdf,
|
||||
zero_case,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,13 +60,13 @@ impl Distribution<f64> for Exp1 {
|
|||
///
|
||||
/// 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")]
|
||||
#[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
|
||||
lambda_inverse: f64,
|
||||
}
|
||||
|
||||
impl Exp {
|
||||
|
@ -71,7 +75,9 @@ impl Exp {
|
|||
#[inline]
|
||||
pub fn new(lambda: f64) -> Exp {
|
||||
assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
|
||||
Exp { lambda_inverse: 1.0 / lambda }
|
||||
Exp {
|
||||
lambda_inverse: 1.0 / lambda,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,8 +90,8 @@ impl Distribution<f64> for Exp {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::distributions::Distribution;
|
||||
use super::Exp;
|
||||
use crate::distributions::Distribution;
|
||||
|
||||
#[test]
|
||||
fn test_exp() {
|
||||
|
|
|
@ -8,18 +8,17 @@
|
|||
|
||||
//! Basic floating-point number distributions
|
||||
|
||||
use core::mem;
|
||||
use crate::Rng;
|
||||
use crate::distributions::{Distribution, Standard};
|
||||
use crate::distributions::utils::FloatSIMDUtils;
|
||||
#[cfg(feature="simd_support")]
|
||||
use packed_simd::*;
|
||||
use crate::distributions::{Distribution, Standard};
|
||||
use crate::Rng;
|
||||
use core::mem;
|
||||
#[cfg(feature = "simd_support")] use packed_simd::*;
|
||||
|
||||
/// A distribution to sample floating point numbers uniformly in the half-open
|
||||
/// interval `(0, 1]`, i.e. including 1 but not 0.
|
||||
///
|
||||
/// All values that can be generated are of the form `n * ε/2`. For `f32`
|
||||
/// the 23 most significant random bits of a `u32` are used and for `f64` the
|
||||
/// the 24 most significant random bits of a `u32` are used and for `f64` the
|
||||
/// 53 most significant bits of a `u64` are used. The conversion uses the
|
||||
/// multiplicative method.
|
||||
///
|
||||
|
@ -46,7 +45,7 @@ pub struct OpenClosed01;
|
|||
/// interval `(0, 1)`, i.e. not including either endpoint.
|
||||
///
|
||||
/// All values that can be generated are of the form `n * ε + ε/2`. For `f32`
|
||||
/// the 22 most significant random bits of an `u32` are used, for `f64` 52 from
|
||||
/// the 23 most significant random bits of an `u32` are used, for `f64` 52 from
|
||||
/// an `u64`. The conversion uses a transmute-based method.
|
||||
///
|
||||
/// See also: [`Standard`] which samples from `[0, 1)`, [`OpenClosed01`]
|
||||
|
@ -149,20 +148,20 @@ macro_rules! float_impls {
|
|||
float_impls! { f32, u32, f32, u32, 23, 127 }
|
||||
float_impls! { f64, u64, f64, u64, 52, 1023 }
|
||||
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
float_impls! { f32x2, u32x2, f32, u32, 23, 127 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
float_impls! { f32x4, u32x4, f32, u32, 23, 127 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
float_impls! { f32x8, u32x8, f32, u32, 23, 127 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
float_impls! { f32x16, u32x16, f32, u32, 23, 127 }
|
||||
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
float_impls! { f64x2, u64x2, f64, u64, 52, 1023 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
float_impls! { f64x4, u64x4, f64, u64, 52, 1023 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
float_impls! { f64x8, u64x8, f64, u64, 52, 1023 }
|
||||
|
||||
|
||||
|
@ -188,8 +187,7 @@ mod tests {
|
|||
|
||||
// OpenClosed01
|
||||
let mut zeros = StepRng::new(0, 0);
|
||||
assert_eq!(zeros.sample::<$ty, _>(OpenClosed01),
|
||||
0.0 + $EPSILON / 2.0);
|
||||
assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), 0.0 + $EPSILON / 2.0);
|
||||
let mut one = StepRng::new(1 << 8 | 1 << (8 + 32), 0);
|
||||
assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON);
|
||||
let mut max = StepRng::new(!0, 0);
|
||||
|
@ -203,16 +201,16 @@ mod tests {
|
|||
let mut max = StepRng::new(!0, 0);
|
||||
assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
test_f32! { f32_edge_cases, f32, 0.0, EPSILON32 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
test_f32! { f32x2_edge_cases, f32x2, f32x2::splat(0.0), f32x2::splat(EPSILON32) }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
test_f32! { f32x4_edge_cases, f32x4, f32x4::splat(0.0), f32x4::splat(EPSILON32) }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
test_f32! { f32x8_edge_cases, f32x8, f32x8::splat(0.0), f32x8::splat(EPSILON32) }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
test_f32! { f32x16_edge_cases, f32x16, f32x16::splat(0.0), f32x16::splat(EPSILON32) }
|
||||
|
||||
macro_rules! test_f64 {
|
||||
|
@ -229,8 +227,7 @@ mod tests {
|
|||
|
||||
// OpenClosed01
|
||||
let mut zeros = StepRng::new(0, 0);
|
||||
assert_eq!(zeros.sample::<$ty, _>(OpenClosed01),
|
||||
0.0 + $EPSILON / 2.0);
|
||||
assert_eq!(zeros.sample::<$ty, _>(OpenClosed01), 0.0 + $EPSILON / 2.0);
|
||||
let mut one = StepRng::new(1 << 11, 0);
|
||||
assert_eq!(one.sample::<$ty, _>(OpenClosed01), $EPSILON);
|
||||
let mut max = StepRng::new(!0, 0);
|
||||
|
@ -244,20 +241,20 @@ mod tests {
|
|||
let mut max = StepRng::new(!0, 0);
|
||||
assert_eq!(max.sample::<$ty, _>(Open01), 1.0 - $EPSILON / 2.0);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
test_f64! { f64_edge_cases, f64, 0.0, EPSILON64 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
test_f64! { f64x2_edge_cases, f64x2, f64x2::splat(0.0), f64x2::splat(EPSILON64) }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
test_f64! { f64x4_edge_cases, f64x4, f64x4::splat(0.0), f64x4::splat(EPSILON64) }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
test_f64! { f64x8_edge_cases, f64x8, f64x8::splat(0.0), f64x8::splat(EPSILON64) }
|
||||
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
fn test_samples<T: Copy + core::fmt::Debug + PartialEq, D: Distribution<T>>(
|
||||
distr: &D, zero: T, expected: &[T]
|
||||
distr: &D, zero: T, expected: &[T],
|
||||
) {
|
||||
let mut rng = crate::test::rng(0x6f44f5646c2a7334);
|
||||
let mut buf = [zero; 3];
|
||||
|
@ -266,33 +263,45 @@ mod tests {
|
|||
}
|
||||
assert_eq!(&buf, expected);
|
||||
}
|
||||
|
||||
|
||||
test_samples(&Standard, 0f32, &[0.0035963655, 0.7346052, 0.09778172]);
|
||||
test_samples(&Standard, 0f64, &[0.7346051961657583,
|
||||
0.20298547462974248, 0.8166436635290655]);
|
||||
|
||||
test_samples(&Standard, 0f64, &[
|
||||
0.7346051961657583,
|
||||
0.20298547462974248,
|
||||
0.8166436635290655,
|
||||
]);
|
||||
|
||||
test_samples(&OpenClosed01, 0f32, &[0.003596425, 0.73460525, 0.09778178]);
|
||||
test_samples(&OpenClosed01, 0f64, &[0.7346051961657584,
|
||||
0.2029854746297426, 0.8166436635290656]);
|
||||
|
||||
test_samples(&OpenClosed01, 0f64, &[
|
||||
0.7346051961657584,
|
||||
0.2029854746297426,
|
||||
0.8166436635290656,
|
||||
]);
|
||||
|
||||
test_samples(&Open01, 0f32, &[0.0035963655, 0.73460525, 0.09778172]);
|
||||
test_samples(&Open01, 0f64, &[0.7346051961657584,
|
||||
0.20298547462974248, 0.8166436635290656]);
|
||||
|
||||
#[cfg(feature="simd_support")] {
|
||||
test_samples(&Open01, 0f64, &[
|
||||
0.7346051961657584,
|
||||
0.20298547462974248,
|
||||
0.8166436635290656,
|
||||
]);
|
||||
|
||||
#[cfg(feature = "simd_support")]
|
||||
{
|
||||
// We only test a sub-set of types here. Values are identical to
|
||||
// non-SIMD types; we assume this pattern continues across all
|
||||
// SIMD types.
|
||||
|
||||
|
||||
test_samples(&Standard, f32x2::new(0.0, 0.0), &[
|
||||
f32x2::new(0.0035963655, 0.7346052),
|
||||
f32x2::new(0.09778172, 0.20298547),
|
||||
f32x2::new(0.34296435, 0.81664366)]);
|
||||
|
||||
f32x2::new(0.0035963655, 0.7346052),
|
||||
f32x2::new(0.09778172, 0.20298547),
|
||||
f32x2::new(0.34296435, 0.81664366),
|
||||
]);
|
||||
|
||||
test_samples(&Standard, f64x2::new(0.0, 0.0), &[
|
||||
f64x2::new(0.7346051961657583, 0.20298547462974248),
|
||||
f64x2::new(0.8166436635290655, 0.7423708925400552),
|
||||
f64x2::new(0.16387782224016323, 0.9087068770169618)]);
|
||||
f64x2::new(0.7346051961657583, 0.20298547462974248),
|
||||
f64x2::new(0.8166436635290655, 0.7423708925400552),
|
||||
f64x2::new(0.16387782224016323, 0.9087068770169618),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
//! The Gamma and derived distributions.
|
||||
#![allow(deprecated)]
|
||||
|
||||
use self::GammaRepr::*;
|
||||
use self::ChiSquaredRepr::*;
|
||||
use self::GammaRepr::*;
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::normal::StandardNormal;
|
||||
use crate::distributions::{Distribution, Exp, Open01};
|
||||
use crate::Rng;
|
||||
|
||||
/// The Gamma distribution `Gamma(shape, scale)` distribution.
|
||||
///
|
||||
|
@ -37,7 +37,7 @@ use crate::distributions::{Distribution, Exp, Open01};
|
|||
/// 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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Gamma {
|
||||
repr: GammaRepr,
|
||||
|
@ -47,7 +47,7 @@ pub struct Gamma {
|
|||
enum GammaRepr {
|
||||
Large(GammaLargeShape),
|
||||
One(Exp),
|
||||
Small(GammaSmallShape)
|
||||
Small(GammaSmallShape),
|
||||
}
|
||||
|
||||
// These two helpers could be made public, but saving the
|
||||
|
@ -67,7 +67,7 @@ enum GammaRepr {
|
|||
#[derive(Clone, Copy, Debug)]
|
||||
struct GammaSmallShape {
|
||||
inv_shape: f64,
|
||||
large_shape: GammaLargeShape
|
||||
large_shape: GammaLargeShape,
|
||||
}
|
||||
|
||||
/// Gamma distribution where the shape parameter is larger than 1.
|
||||
|
@ -78,7 +78,7 @@ struct GammaSmallShape {
|
|||
struct GammaLargeShape {
|
||||
scale: f64,
|
||||
c: f64,
|
||||
d: f64
|
||||
d: f64,
|
||||
}
|
||||
|
||||
impl Gamma {
|
||||
|
@ -106,7 +106,7 @@ impl GammaSmallShape {
|
|||
fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
|
||||
GammaSmallShape {
|
||||
inv_shape: 1. / shape,
|
||||
large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
|
||||
large_shape: GammaLargeShape::new_raw(shape + 1.0, scale),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ impl GammaLargeShape {
|
|||
GammaLargeShape {
|
||||
scale,
|
||||
c: 1. / (9. * d).sqrt(),
|
||||
d
|
||||
d,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,17 +143,19 @@ impl Distribution<f64> for GammaLargeShape {
|
|||
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
|
||||
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
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +168,7 @@ impl Distribution<f64> for GammaLargeShape {
|
|||
/// 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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ChiSquared {
|
||||
repr: ChiSquaredRepr,
|
||||
|
@ -202,7 +204,7 @@ impl Distribution<f64> for ChiSquared {
|
|||
let norm = rng.sample(StandardNormal);
|
||||
norm * norm
|
||||
}
|
||||
DoFAnythingElse(ref g) => g.sample(rng)
|
||||
DoFAnythingElse(ref g) => g.sample(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +214,7 @@ impl Distribution<f64> for ChiSquared {
|
|||
/// 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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct FisherF {
|
||||
numer: ChiSquared,
|
||||
|
@ -232,7 +234,7 @@ impl FisherF {
|
|||
FisherF {
|
||||
numer: ChiSquared::new(m),
|
||||
denom: ChiSquared::new(n),
|
||||
dof_ratio: n / m
|
||||
dof_ratio: n / m,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,11 +246,11 @@ impl Distribution<f64> for FisherF {
|
|||
|
||||
/// The Student t distribution, `t(nu)`, where `nu` is the degrees of
|
||||
/// freedom.
|
||||
#[deprecated(since="0.7.0", note="moved to rand_distr crate")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StudentT {
|
||||
chi: ChiSquared,
|
||||
dof: f64
|
||||
dof: f64,
|
||||
}
|
||||
|
||||
impl StudentT {
|
||||
|
@ -258,7 +260,7 @@ impl StudentT {
|
|||
assert!(n > 0.0, "StudentT::new called with `n <= 0`");
|
||||
StudentT {
|
||||
chi: ChiSquared::new(n),
|
||||
dof: n
|
||||
dof: n,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +272,7 @@ impl Distribution<f64> for StudentT {
|
|||
}
|
||||
|
||||
/// The Beta distribution with shape parameters `alpha` and `beta`.
|
||||
#[deprecated(since="0.7.0", note="moved to rand_distr crate")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Beta {
|
||||
gamma_a: Gamma,
|
||||
|
@ -301,8 +303,8 @@ impl Distribution<f64> for Beta {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{Beta, ChiSquared, FisherF, StudentT};
|
||||
use crate::distributions::Distribution;
|
||||
use super::{Beta, ChiSquared, StudentT, FisherF};
|
||||
|
||||
const N: u32 = 100;
|
||||
|
||||
|
|
|
@ -8,16 +8,14 @@
|
|||
|
||||
//! The implementations of the `Standard` distribution for integer types.
|
||||
|
||||
use crate::{Rng};
|
||||
use crate::distributions::{Distribution, Standard};
|
||||
use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroUsize};
|
||||
#[cfg(not(target_os = "emscripten"))] use core::num::NonZeroU128;
|
||||
#[cfg(feature="simd_support")]
|
||||
use packed_simd::*;
|
||||
#[cfg(all(target_arch = "x86", feature="nightly"))]
|
||||
use core::arch::x86::*;
|
||||
#[cfg(all(target_arch = "x86_64", feature="nightly"))]
|
||||
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(not(target_os = "emscripten"))] use core::num::NonZeroU128;
|
||||
use core::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
|
||||
#[cfg(feature = "simd_support")] use packed_simd::*;
|
||||
|
||||
impl Distribution<u8> for Standard {
|
||||
#[inline]
|
||||
|
@ -80,14 +78,15 @@ macro_rules! impl_int_from_uint {
|
|||
rng.gen::<$uty>() as $ty
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_int_from_uint! { i8, u8 }
|
||||
impl_int_from_uint! { i16, u16 }
|
||||
impl_int_from_uint! { i32, u32 }
|
||||
impl_int_from_uint! { i64, u64 }
|
||||
#[cfg(not(target_os = "emscripten"))] impl_int_from_uint! { i128, u128 }
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impl_int_from_uint! { i128, u128 }
|
||||
impl_int_from_uint! { isize, usize }
|
||||
|
||||
macro_rules! impl_nzint {
|
||||
|
@ -101,17 +100,18 @@ macro_rules! impl_nzint {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_nzint!(NonZeroU8, NonZeroU8::new);
|
||||
impl_nzint!(NonZeroU16, NonZeroU16::new);
|
||||
impl_nzint!(NonZeroU32, NonZeroU32::new);
|
||||
impl_nzint!(NonZeroU64, NonZeroU64::new);
|
||||
#[cfg(not(target_os = "emscripten"))] impl_nzint!(NonZeroU128, NonZeroU128::new);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impl_nzint!(NonZeroU128, NonZeroU128::new);
|
||||
impl_nzint!(NonZeroUsize, NonZeroUsize::new);
|
||||
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
macro_rules! simd_impl {
|
||||
($(($intrinsic:ident, $vec:ty),)+) => {$(
|
||||
impl Distribution<$intrinsic> for Standard {
|
||||
|
@ -141,29 +141,33 @@ macro_rules! simd_impl {
|
|||
};
|
||||
}
|
||||
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
simd_impl!(16, u8x2, i8x2,);
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
simd_impl!(32, u8x4, i8x4, u16x2, i16x2,);
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
simd_impl!(64, u8x8, i8x8, u16x4, i16x4, u32x2, i32x2,);
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
simd_impl!(128, u8x16, i8x16, u16x8, i16x8, u32x4, i32x4, u64x2, i64x2,);
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
simd_impl!(256, u8x32, i8x32, u16x16, i16x16, u32x8, i32x8, u64x4, i64x4,);
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
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")))]
|
||||
#[cfg(all(
|
||||
feature = "simd_support",
|
||||
feature = "nightly",
|
||||
any(target_arch = "x86", target_arch = "x86_64")
|
||||
))]
|
||||
simd_impl!((__m64, u8x8), (__m128i, u8x16), (__m256i, u8x32),);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_integers() {
|
||||
let mut rng = crate::test::rng(806);
|
||||
|
||||
|
||||
rng.sample::<isize, _>(Standard);
|
||||
rng.sample::<i8, _>(Standard);
|
||||
rng.sample::<i16, _>(Standard);
|
||||
|
@ -171,7 +175,7 @@ mod tests {
|
|||
rng.sample::<i64, _>(Standard);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
rng.sample::<i128, _>(Standard);
|
||||
|
||||
|
||||
rng.sample::<usize, _>(Standard);
|
||||
rng.sample::<u8, _>(Standard);
|
||||
rng.sample::<u16, _>(Standard);
|
||||
|
@ -180,14 +184,11 @@ mod tests {
|
|||
#[cfg(not(target_os = "emscripten"))]
|
||||
rng.sample::<u128, _>(Standard);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
fn test_samples<T: Copy + core::fmt::Debug + PartialEq>(
|
||||
zero: T, expected: &[T]
|
||||
)
|
||||
where Standard: Distribution<T>
|
||||
{
|
||||
fn test_samples<T: Copy + core::fmt::Debug + PartialEq>(zero: T, expected: &[T])
|
||||
where Standard: Distribution<T> {
|
||||
let mut rng = crate::test::rng(807);
|
||||
let mut buf = [zero; 3];
|
||||
for x in &mut buf {
|
||||
|
@ -195,49 +196,84 @@ mod tests {
|
|||
}
|
||||
assert_eq!(&buf, expected);
|
||||
}
|
||||
|
||||
|
||||
test_samples(0u8, &[9, 247, 111]);
|
||||
test_samples(0u16, &[32265, 42999, 38255]);
|
||||
test_samples(0u32, &[2220326409, 2575017975, 2018088303]);
|
||||
test_samples(0u64, &[11059617991457472009,
|
||||
16096616328739788143, 1487364411147516184]);
|
||||
test_samples(0u128, &[296930161868957086625409848350820761097,
|
||||
145644820879247630242265036535529306392,
|
||||
111087889832015897993126088499035356354]);
|
||||
test_samples(0u64, &[
|
||||
11059617991457472009,
|
||||
16096616328739788143,
|
||||
1487364411147516184,
|
||||
]);
|
||||
test_samples(0u128, &[
|
||||
296930161868957086625409848350820761097,
|
||||
145644820879247630242265036535529306392,
|
||||
111087889832015897993126088499035356354,
|
||||
]);
|
||||
#[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))]
|
||||
test_samples(0usize, &[2220326409, 2575017975, 2018088303]);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
test_samples(0usize, &[11059617991457472009,
|
||||
16096616328739788143, 1487364411147516184]);
|
||||
|
||||
test_samples(0usize, &[
|
||||
11059617991457472009,
|
||||
16096616328739788143,
|
||||
1487364411147516184,
|
||||
]);
|
||||
|
||||
test_samples(0i8, &[9, -9, 111]);
|
||||
// Skip further i* types: they are simple reinterpretation of u* samples
|
||||
|
||||
#[cfg(feature="simd_support")] {
|
||||
|
||||
#[cfg(feature = "simd_support")]
|
||||
{
|
||||
// We only test a sub-set of types here and make assumptions about the rest.
|
||||
|
||||
test_samples(u8x2::default(), &[u8x2::new(9, 126),
|
||||
u8x2::new(247, 167), u8x2::new(111, 149)]);
|
||||
test_samples(u8x4::default(), &[u8x4::new(9, 126, 87, 132),
|
||||
u8x4::new(247, 167, 123, 153), u8x4::new(111, 149, 73, 120)]);
|
||||
|
||||
test_samples(u8x2::default(), &[
|
||||
u8x2::new(9, 126),
|
||||
u8x2::new(247, 167),
|
||||
u8x2::new(111, 149),
|
||||
]);
|
||||
test_samples(u8x4::default(), &[
|
||||
u8x4::new(9, 126, 87, 132),
|
||||
u8x4::new(247, 167, 123, 153),
|
||||
u8x4::new(111, 149, 73, 120),
|
||||
]);
|
||||
test_samples(u8x8::default(), &[
|
||||
u8x8::new(9, 126, 87, 132, 247, 167, 123, 153),
|
||||
u8x8::new(111, 149, 73, 120, 68, 171, 98, 223),
|
||||
u8x8::new(24, 121, 1, 50, 13, 46, 164, 20)]);
|
||||
|
||||
u8x8::new(9, 126, 87, 132, 247, 167, 123, 153),
|
||||
u8x8::new(111, 149, 73, 120, 68, 171, 98, 223),
|
||||
u8x8::new(24, 121, 1, 50, 13, 46, 164, 20),
|
||||
]);
|
||||
|
||||
test_samples(i64x8::default(), &[
|
||||
i64x8::new(-7387126082252079607, -2350127744969763473,
|
||||
1487364411147516184, 7895421560427121838,
|
||||
602190064936008898, 6022086574635100741,
|
||||
-5080089175222015595, -4066367846667249123),
|
||||
i64x8::new(9180885022207963908, 3095981199532211089,
|
||||
6586075293021332726, 419343203796414657,
|
||||
3186951873057035255, 5287129228749947252,
|
||||
444726432079249540, -1587028029513790706),
|
||||
i64x8::new(6075236523189346388, 1351763722368165432,
|
||||
-6192309979959753740, -7697775502176768592,
|
||||
-4482022114172078123, 7522501477800909500,
|
||||
-1837258847956201231, -586926753024886735)]);
|
||||
i64x8::new(
|
||||
-7387126082252079607,
|
||||
-2350127744969763473,
|
||||
1487364411147516184,
|
||||
7895421560427121838,
|
||||
602190064936008898,
|
||||
6022086574635100741,
|
||||
-5080089175222015595,
|
||||
-4066367846667249123,
|
||||
),
|
||||
i64x8::new(
|
||||
9180885022207963908,
|
||||
3095981199532211089,
|
||||
6586075293021332726,
|
||||
419343203796414657,
|
||||
3186951873057035255,
|
||||
5287129228749947252,
|
||||
444726432079249540,
|
||||
-1587028029513790706,
|
||||
),
|
||||
i64x8::new(
|
||||
6075236523189346388,
|
||||
1351763722368165432,
|
||||
-6192309979959753740,
|
||||
-7697775502176768592,
|
||||
-4482022114172078123,
|
||||
7522501477800909500,
|
||||
-1837258847956201231,
|
||||
-586926753024886735,
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,17 +31,17 @@
|
|||
//! # The `Standard` distribution
|
||||
//!
|
||||
//! The [`Standard`] distribution is important to mention. This is the
|
||||
//! distribution used by [`Rng::gen()`] and represents the "default" way to
|
||||
//! distribution used by [`Rng::gen`] and represents the "default" way to
|
||||
//! produce a random value for many different types, including most primitive
|
||||
//! types, tuples, arrays, and a few derived types. See the documentation of
|
||||
//! [`Standard`] for more details.
|
||||
//!
|
||||
//! Implementing `Distribution<T>` for [`Standard`] for user types `T` makes it
|
||||
//! possible to generate type `T` with [`Rng::gen()`], and by extension also
|
||||
//! with the [`random()`] function.
|
||||
//! possible to generate type `T` with [`Rng::gen`], and by extension also
|
||||
//! with the [`random`] function.
|
||||
//!
|
||||
//! ## Random characters
|
||||
//!
|
||||
//!
|
||||
//! [`Alphanumeric`] is a simple distribution to sample random letters and
|
||||
//! numbers of the `char` type; in contrast [`Standard`] may sample any valid
|
||||
//! `char`.
|
||||
|
@ -89,78 +89,83 @@
|
|||
//! [`rand_distr`]: https://crates.io/crates/rand_distr
|
||||
//! [`statrs`]: https://crates.io/crates/statrs
|
||||
|
||||
//! [`Alphanumeric`]: distributions::Alphanumeric
|
||||
//! [`Bernoulli`]: distributions::Bernoulli
|
||||
//! [`Open01`]: distributions::Open01
|
||||
//! [`OpenClosed01`]: distributions::OpenClosed01
|
||||
//! [`Standard`]: distributions::Standard
|
||||
//! [`Uniform`]: distributions::Uniform
|
||||
//! [`Uniform::new`]: distributions::Uniform::new
|
||||
//! [`Uniform::new_inclusive`]: distributions::Uniform::new_inclusive
|
||||
//! [`weighted`]: distributions::weighted
|
||||
//! [`random`]: crate::random
|
||||
//! [`rand_distr`]: https://crates.io/crates/rand_distr
|
||||
//! [`statrs`]: https://crates.io/crates/statrs
|
||||
|
||||
use core::iter;
|
||||
use crate::Rng;
|
||||
use core::iter;
|
||||
|
||||
pub use self::bernoulli::{Bernoulli, BernoulliError};
|
||||
pub use self::float::{Open01, OpenClosed01};
|
||||
pub use self::other::Alphanumeric;
|
||||
#[doc(inline)] pub use self::uniform::Uniform;
|
||||
pub use self::float::{OpenClosed01, Open01};
|
||||
pub use self::bernoulli::{Bernoulli, BernoulliError};
|
||||
#[cfg(feature="alloc")] pub use self::weighted::{WeightedIndex, WeightedError};
|
||||
#[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::unit_sphere::UnitSphereSurface;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::binomial::Binomial;
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::unit_circle::UnitCircle;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::cauchy::Cauchy;
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::gamma::{Gamma, ChiSquared, FisherF,
|
||||
StudentT, Beta};
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::dirichlet::Dirichlet;
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::normal::{Normal, LogNormal, StandardNormal};
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::exponential::{Exp, Exp1};
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::exponential::{Exp, Exp1};
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::gamma::{Beta, ChiSquared, FisherF, Gamma, StudentT};
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::pareto::Pareto;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::normal::{LogNormal, Normal, StandardNormal};
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::poisson::Poisson;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::pareto::Pareto;
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::binomial::Binomial;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::poisson::Poisson;
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::cauchy::Cauchy;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::triangular::Triangular;
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::dirichlet::Dirichlet;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::unit_circle::UnitCircle;
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::triangular::Triangular;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::unit_sphere::UnitSphereSurface;
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::weibull::Weibull;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::weibull::Weibull;
|
||||
|
||||
pub mod uniform;
|
||||
mod bernoulli;
|
||||
#[cfg(feature="alloc")] pub mod weighted;
|
||||
#[cfg(feature="std")] mod unit_sphere;
|
||||
#[cfg(feature="std")] mod unit_circle;
|
||||
#[cfg(feature="std")] mod gamma;
|
||||
#[cfg(feature="std")] mod normal;
|
||||
#[cfg(feature="std")] mod exponential;
|
||||
#[cfg(feature="std")] mod pareto;
|
||||
#[cfg(feature="std")] mod poisson;
|
||||
#[cfg(feature="std")] mod binomial;
|
||||
#[cfg(feature="std")] mod cauchy;
|
||||
#[cfg(feature="std")] mod dirichlet;
|
||||
#[cfg(feature="std")] mod triangular;
|
||||
#[cfg(feature="std")] mod weibull;
|
||||
#[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;
|
||||
|
||||
mod float;
|
||||
#[doc(hidden)] pub mod hidden_export {
|
||||
pub use super::float::IntoFloat; // used by rand_distr
|
||||
#[doc(hidden)]
|
||||
pub mod hidden_export {
|
||||
pub use super::float::IntoFloat; // used by rand_distr
|
||||
}
|
||||
mod integer;
|
||||
mod other;
|
||||
mod utils;
|
||||
#[cfg(feature="std")] mod ziggurat_tables;
|
||||
#[cfg(feature = "std")] mod ziggurat_tables;
|
||||
|
||||
/// Types (distributions) that can be used to create a random instance of `T`.
|
||||
///
|
||||
|
@ -215,7 +220,9 @@ pub trait Distribution<T> {
|
|||
/// }
|
||||
/// ```
|
||||
fn sample_iter<R>(self, rng: R) -> DistIter<Self, R, T>
|
||||
where R: Rng, Self: Sized
|
||||
where
|
||||
R: Rng,
|
||||
Self: Sized,
|
||||
{
|
||||
DistIter {
|
||||
distr: self,
|
||||
|
@ -247,7 +254,9 @@ pub struct DistIter<D, R, T> {
|
|||
}
|
||||
|
||||
impl<D, R, T> Iterator for DistIter<D, R, T>
|
||||
where D: Distribution<T>, R: Rng
|
||||
where
|
||||
D: Distribution<T>,
|
||||
R: Rng,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
|
@ -265,11 +274,19 @@ impl<D, R, T> Iterator for DistIter<D, R, T>
|
|||
}
|
||||
|
||||
impl<D, R, T> iter::FusedIterator for DistIter<D, R, T>
|
||||
where D: Distribution<T>, R: Rng {}
|
||||
where
|
||||
D: Distribution<T>,
|
||||
R: Rng,
|
||||
{
|
||||
}
|
||||
|
||||
#[cfg(features = "nightly")]
|
||||
impl<D, R, T> iter::TrustedLen for DistIter<D, R, T>
|
||||
where D: Distribution<T>, R: Rng {}
|
||||
where
|
||||
D: Distribution<T>,
|
||||
R: Rng,
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// A generic random value distribution, implemented for many primitive types.
|
||||
|
@ -337,7 +354,7 @@ impl<D, R, T> iter::TrustedLen for DistIter<D, R, T>
|
|||
/// the half-open interval `[0, 1)`, i.e. including 0 but not 1.
|
||||
///
|
||||
/// All values that can be generated are of the form `n * ε/2`. For `f32`
|
||||
/// the 23 most significant random bits of a `u32` are used and for `f64` the
|
||||
/// the 24 most significant random bits of a `u32` are used and for `f64` the
|
||||
/// 53 most significant bits of a `u64` are used. The conversion uses the
|
||||
/// multiplicative method: `(rng.gen::<$uty>() >> N) as $ty * (ε/2)`.
|
||||
///
|
||||
|
@ -355,8 +372,8 @@ pub struct Standard;
|
|||
|
||||
#[cfg(all(test, feature = "std"))]
|
||||
mod tests {
|
||||
use crate::Rng;
|
||||
use super::{Distribution, Uniform};
|
||||
use crate::Rng;
|
||||
|
||||
#[test]
|
||||
fn test_distributions_iter() {
|
||||
|
@ -366,16 +383,18 @@ mod tests {
|
|||
let results: Vec<f32> = distr.sample_iter(&mut rng).take(100).collect();
|
||||
println!("{:?}", results);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_make_an_iter() {
|
||||
fn ten_dice_rolls_other_than_five<'a, R: Rng>(rng: &'a mut R) -> impl Iterator<Item = i32> + 'a {
|
||||
fn ten_dice_rolls_other_than_five<'a, R: Rng>(
|
||||
rng: &'a mut R,
|
||||
) -> impl Iterator<Item = i32> + 'a {
|
||||
Uniform::new_inclusive(1, 6)
|
||||
.sample_iter(rng)
|
||||
.filter(|x| *x != 5)
|
||||
.take(10)
|
||||
}
|
||||
|
||||
|
||||
let mut rng = crate::test::rng(211);
|
||||
let mut count = 0;
|
||||
for val in ten_dice_rolls_other_than_five(&mut rng) {
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
//! The normal and derived distributions.
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::{ziggurat_tables, Distribution, Open01};
|
||||
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
|
||||
|
@ -26,7 +26,7 @@ use crate::distributions::utils::ziggurat;
|
|||
/// 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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct StandardNormal;
|
||||
|
||||
|
@ -34,7 +34,7 @@ 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()
|
||||
(-x * x / 2.0).exp()
|
||||
}
|
||||
#[inline]
|
||||
fn zero_case<R: Rng + ?Sized>(rng: &mut R, u: f64) -> f64 {
|
||||
|
@ -55,13 +55,21 @@ impl Distribution<f64> for StandardNormal {
|
|||
y = y_.ln();
|
||||
}
|
||||
|
||||
if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
|
||||
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)
|
||||
ziggurat(
|
||||
rng,
|
||||
true, // this is symmetric
|
||||
&ziggurat_tables::ZIG_NORM_X,
|
||||
&ziggurat_tables::ZIG_NORM_F,
|
||||
pdf,
|
||||
zero_case,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,12 +77,12 @@ impl Distribution<f64> for StandardNormal {
|
|||
///
|
||||
/// 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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Normal {
|
||||
mean: f64,
|
||||
|
@ -91,10 +99,7 @@ impl Normal {
|
|||
#[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
|
||||
}
|
||||
Normal { mean, std_dev }
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for Normal {
|
||||
|
@ -109,10 +114,10 @@ impl Distribution<f64> for Normal {
|
|||
///
|
||||
/// 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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct LogNormal {
|
||||
norm: Normal
|
||||
norm: Normal,
|
||||
}
|
||||
|
||||
impl LogNormal {
|
||||
|
@ -125,7 +130,9 @@ impl LogNormal {
|
|||
#[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) }
|
||||
LogNormal {
|
||||
norm: Normal::new(mean, std_dev),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Distribution<f64> for LogNormal {
|
||||
|
@ -136,8 +143,8 @@ impl Distribution<f64> for LogNormal {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{LogNormal, Normal};
|
||||
use crate::distributions::Distribution;
|
||||
use super::{Normal, LogNormal};
|
||||
|
||||
#[test]
|
||||
fn test_normal() {
|
||||
|
|
|
@ -11,21 +11,21 @@
|
|||
use core::char;
|
||||
use core::num::Wrapping;
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::{Distribution, Standard, Uniform};
|
||||
use crate::Rng;
|
||||
|
||||
// ----- Sampling distributions -----
|
||||
|
||||
/// Sample a `char`, uniformly distributed over ASCII letters and numbers:
|
||||
/// a-z, A-Z and 0-9.
|
||||
///
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter;
|
||||
/// use rand::{Rng, thread_rng};
|
||||
/// use rand::distributions::Alphanumeric;
|
||||
///
|
||||
///
|
||||
/// let mut rng = thread_rng();
|
||||
/// let chars: String = iter::repeat(())
|
||||
/// .map(|()| rng.sample(Alphanumeric))
|
||||
|
@ -63,8 +63,7 @@ impl Distribution<char> for Standard {
|
|||
impl Distribution<char> for Alphanumeric {
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
|
||||
const RANGE: u32 = 26 + 26 + 10;
|
||||
const GEN_ASCII_STR_CHARSET: &[u8] =
|
||||
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
|
||||
const GEN_ASCII_STR_CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
|
||||
abcdefghijklmnopqrstuvwxyz\
|
||||
0123456789";
|
||||
// We can pick from 62 characters. This is so close to a power of 2, 64,
|
||||
|
@ -74,7 +73,7 @@ impl Distribution<char> for Alphanumeric {
|
|||
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] as char;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,20 +117,22 @@ macro_rules! tuple_impl {
|
|||
impl Distribution<()> for Standard {
|
||||
#[allow(clippy::unused_unit)]
|
||||
#[inline]
|
||||
fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () { () }
|
||||
fn sample<R: Rng + ?Sized>(&self, _: &mut R) -> () {
|
||||
()
|
||||
}
|
||||
}
|
||||
tuple_impl!{A}
|
||||
tuple_impl!{A, B}
|
||||
tuple_impl!{A, B, C}
|
||||
tuple_impl!{A, B, C, D}
|
||||
tuple_impl!{A, B, C, D, E}
|
||||
tuple_impl!{A, B, C, D, E, F}
|
||||
tuple_impl!{A, B, C, D, E, F, G}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I, J}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K}
|
||||
tuple_impl!{A, B, C, D, E, F, G, H, I, J, K, L}
|
||||
tuple_impl! {A}
|
||||
tuple_impl! {A, B}
|
||||
tuple_impl! {A, B, C}
|
||||
tuple_impl! {A, B, C, D}
|
||||
tuple_impl! {A, B, C, D, E}
|
||||
tuple_impl! {A, B, C, D, E, F}
|
||||
tuple_impl! {A, B, C, D, E, F, G}
|
||||
tuple_impl! {A, B, C, D, E, F, G, H}
|
||||
tuple_impl! {A, B, C, D, E, F, G, H, I}
|
||||
tuple_impl! {A, B, C, D, E, F, G, H, I, J}
|
||||
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
|
||||
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}
|
||||
|
||||
macro_rules! array_impl {
|
||||
// recursive, given at least one type parameter:
|
||||
|
@ -153,9 +154,11 @@ macro_rules! array_impl {
|
|||
};
|
||||
}
|
||||
|
||||
array_impl!{32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}
|
||||
array_impl! {32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}
|
||||
|
||||
impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> {
|
||||
impl<T> Distribution<Option<T>> for Standard
|
||||
where Standard: Distribution<T>
|
||||
{
|
||||
#[inline]
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<T> {
|
||||
// UFCS is needed here: https://github.com/rust-lang/rust/issues/24066
|
||||
|
@ -167,7 +170,9 @@ impl<T> Distribution<Option<T>> for Standard where Standard: Distribution<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> {
|
||||
impl<T> Distribution<Wrapping<T>> for Standard
|
||||
where Standard: Distribution<T>
|
||||
{
|
||||
#[inline]
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Wrapping<T> {
|
||||
Wrapping(rng.gen())
|
||||
|
@ -179,17 +184,17 @@ impl<T> Distribution<Wrapping<T>> for Standard where Standard: Distribution<T> {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::RngCore;
|
||||
#[cfg(all(not(feature="std"), feature="alloc"))] use alloc::string::String;
|
||||
#[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::string::String;
|
||||
|
||||
#[test]
|
||||
fn test_misc() {
|
||||
let rng: &mut dyn RngCore = &mut crate::test::rng(820);
|
||||
|
||||
|
||||
rng.sample::<char, _>(Standard);
|
||||
rng.sample::<bool, _>(Standard);
|
||||
}
|
||||
|
||||
#[cfg(feature="alloc")]
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[test]
|
||||
fn test_chars() {
|
||||
use core::iter;
|
||||
|
@ -198,7 +203,9 @@ mod tests {
|
|||
// Test by generating a relatively large number of chars, so we also
|
||||
// take the rejection sampling path.
|
||||
let word: String = iter::repeat(())
|
||||
.map(|()| rng.gen::<char>()).take(1000).collect();
|
||||
.map(|()| rng.gen::<char>())
|
||||
.take(1000)
|
||||
.collect();
|
||||
assert!(word.len() != 0);
|
||||
}
|
||||
|
||||
|
@ -217,11 +224,12 @@ mod tests {
|
|||
}
|
||||
assert!(incorrect == false);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
fn test_samples<T: Copy + core::fmt::Debug + PartialEq, D: Distribution<T>>(
|
||||
distr: &D, zero: T, expected: &[T]) {
|
||||
distr: &D, zero: T, expected: &[T],
|
||||
) {
|
||||
let mut rng = crate::test::rng(807);
|
||||
let mut buf = [zero; 5];
|
||||
for x in &mut buf {
|
||||
|
@ -229,25 +237,55 @@ mod tests {
|
|||
}
|
||||
assert_eq!(&buf, expected);
|
||||
}
|
||||
|
||||
test_samples(&Standard, 'a', &['\u{8cdac}', '\u{a346a}', '\u{80120}', '\u{ed692}', '\u{35888}']);
|
||||
|
||||
test_samples(&Standard, 'a', &[
|
||||
'\u{8cdac}',
|
||||
'\u{a346a}',
|
||||
'\u{80120}',
|
||||
'\u{ed692}',
|
||||
'\u{35888}',
|
||||
]);
|
||||
test_samples(&Alphanumeric, 'a', &['h', 'm', 'e', '3', 'M']);
|
||||
test_samples(&Standard, false, &[true, true, false, true, false]);
|
||||
test_samples(&Standard, None as Option<bool>,
|
||||
&[Some(true), None, Some(false), None, Some(false)]);
|
||||
test_samples(&Standard, Wrapping(0i32), &[Wrapping(-2074640887),
|
||||
Wrapping(-1719949321), Wrapping(2018088303),
|
||||
Wrapping(-547181756), Wrapping(838957336)]);
|
||||
|
||||
test_samples(&Standard, None as Option<bool>, &[
|
||||
Some(true),
|
||||
None,
|
||||
Some(false),
|
||||
None,
|
||||
Some(false),
|
||||
]);
|
||||
test_samples(&Standard, Wrapping(0i32), &[
|
||||
Wrapping(-2074640887),
|
||||
Wrapping(-1719949321),
|
||||
Wrapping(2018088303),
|
||||
Wrapping(-547181756),
|
||||
Wrapping(838957336),
|
||||
]);
|
||||
|
||||
// We test only sub-sets of tuple and array impls
|
||||
test_samples(&Standard, (), &[(), (), (), (), ()]);
|
||||
test_samples(&Standard, (false,), &[(true,), (true,), (false,), (true,), (false,)]);
|
||||
test_samples(&Standard, (false,false), &[(true,true), (false,true),
|
||||
(false,false), (true,false), (false,false)]);
|
||||
|
||||
test_samples(&Standard, (false,), &[
|
||||
(true,),
|
||||
(true,),
|
||||
(false,),
|
||||
(true,),
|
||||
(false,),
|
||||
]);
|
||||
test_samples(&Standard, (false, false), &[
|
||||
(true, true),
|
||||
(false, true),
|
||||
(false, false),
|
||||
(true, false),
|
||||
(false, false),
|
||||
]);
|
||||
|
||||
test_samples(&Standard, [0u8; 0], &[[], [], [], [], []]);
|
||||
test_samples(&Standard, [0u8; 3], &[[9, 247, 111],
|
||||
[68, 24, 13], [174, 19, 194],
|
||||
[172, 69, 213], [149, 207, 29]]);
|
||||
test_samples(&Standard, [0u8; 3], &[
|
||||
[9, 247, 111],
|
||||
[68, 24, 13],
|
||||
[174, 19, 194],
|
||||
[172, 69, 213],
|
||||
[149, 207, 29],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
//! The Pareto distribution.
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::Rng;
|
||||
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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Pareto {
|
||||
scale: f64,
|
||||
|
@ -31,7 +31,10 @@ impl Pareto {
|
|||
/// `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 }
|
||||
Pareto {
|
||||
scale,
|
||||
inv_neg_shape: -1.0 / shape,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,8 +47,8 @@ impl Distribution<f64> for Pareto {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::distributions::Distribution;
|
||||
use super::Pareto;
|
||||
use crate::distributions::Distribution;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
|
|
|
@ -10,15 +10,15 @@
|
|||
//! The Poisson distribution.
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::{Distribution, Cauchy};
|
||||
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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Poisson {
|
||||
lambda: f64,
|
||||
|
@ -90,7 +90,8 @@ impl Distribution<u64> for Poisson {
|
|||
// 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)
|
||||
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
|
||||
|
@ -105,11 +106,11 @@ impl Distribution<u64> for Poisson {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::distributions::Distribution;
|
||||
use super::Poisson;
|
||||
use crate::distributions::Distribution;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[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);
|
||||
|
@ -123,7 +124,6 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri doesn't support transcendental functions
|
||||
fn test_poisson_15() {
|
||||
// Take the 'high expected values' path
|
||||
let poisson = Poisson::new(15.0);
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
//! The triangular distribution.
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::{Distribution, Standard};
|
||||
use crate::Rng;
|
||||
|
||||
/// The triangular distribution.
|
||||
#[deprecated(since="0.7.0", note="moved to rand_distr crate")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Triangular {
|
||||
min: f64,
|
||||
|
@ -28,7 +28,6 @@ impl Triangular {
|
|||
/// # Panics
|
||||
///
|
||||
/// If `max < mode`, `mode < max` or `max == min`.
|
||||
///
|
||||
#[inline]
|
||||
pub fn new(min: f64, max: f64, mode: f64) -> Triangular {
|
||||
assert!(max >= mode);
|
||||
|
@ -54,14 +53,19 @@ impl Distribution<f64> for Triangular {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::distributions::Distribution;
|
||||
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),
|
||||
(-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);
|
||||
|
|
|
@ -103,23 +103,20 @@
|
|||
//! [`UniformDuration`]: crate::distributions::uniform::UniformDuration
|
||||
//! [`SampleBorrow::borrow`]: crate::distributions::uniform::SampleBorrow::borrow
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::time::Duration;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core::time::Duration;
|
||||
#[cfg(not(feature = "std"))] use core::time::Duration;
|
||||
#[cfg(feature = "std")] use std::time::Duration;
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::Distribution;
|
||||
use crate::distributions::float::IntoFloat;
|
||||
use crate::distributions::utils::{WideningMultiply, FloatSIMDUtils, FloatAsSIMD, BoolAsSIMD};
|
||||
use crate::distributions::utils::{BoolAsSIMD, FloatAsSIMD, FloatSIMDUtils, WideningMultiply};
|
||||
use crate::distributions::Distribution;
|
||||
use crate::Rng;
|
||||
|
||||
#[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 = "simd_support")] use packed_simd::*;
|
||||
|
||||
/// Sample values uniformly between two bounds.
|
||||
///
|
||||
|
@ -168,8 +165,9 @@ impl<X: SampleUniform> Uniform<X> {
|
|||
/// Create a new `Uniform` instance which samples uniformly from the half
|
||||
/// open range `[low, high)` (excluding `high`). Panics if `low >= high`.
|
||||
pub fn new<B1, B2>(low: B1, high: B2) -> Uniform<X>
|
||||
where B1: SampleBorrow<X> + Sized,
|
||||
B2: SampleBorrow<X> + Sized
|
||||
where
|
||||
B1: SampleBorrow<X> + Sized,
|
||||
B2: SampleBorrow<X> + Sized,
|
||||
{
|
||||
Uniform(X::Sampler::new(low, high))
|
||||
}
|
||||
|
@ -177,8 +175,9 @@ impl<X: SampleUniform> Uniform<X> {
|
|||
/// Create a new `Uniform` instance which samples uniformly from the closed
|
||||
/// range `[low, high]` (inclusive). Panics if `low > high`.
|
||||
pub fn new_inclusive<B1, B2>(low: B1, high: B2) -> Uniform<X>
|
||||
where B1: SampleBorrow<X> + Sized,
|
||||
B2: SampleBorrow<X> + Sized
|
||||
where
|
||||
B1: SampleBorrow<X> + Sized,
|
||||
B2: SampleBorrow<X> + Sized,
|
||||
{
|
||||
Uniform(X::Sampler::new_inclusive(low, high))
|
||||
}
|
||||
|
@ -222,8 +221,9 @@ pub trait UniformSampler: Sized {
|
|||
/// Usually users should not call this directly but instead use
|
||||
/// `Uniform::new`, which asserts that `low < high` before calling this.
|
||||
fn new<B1, B2>(low: B1, high: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized;
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized;
|
||||
|
||||
/// Construct self, with inclusive bounds `[low, high]`.
|
||||
///
|
||||
|
@ -231,8 +231,9 @@ pub trait UniformSampler: Sized {
|
|||
/// `Uniform::new_inclusive`, which asserts that `low <= high` before
|
||||
/// calling this.
|
||||
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized;
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized;
|
||||
|
||||
/// Sample a value.
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X;
|
||||
|
@ -256,10 +257,10 @@ pub trait UniformSampler: Sized {
|
|||
/// <T as SampleUniform>::Sampler::sample_single(lb, ub, &mut rng)
|
||||
/// }
|
||||
/// ```
|
||||
fn sample_single<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
|
||||
fn sample_single<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(low, high);
|
||||
uniform.sample(rng)
|
||||
|
@ -289,13 +290,21 @@ pub trait SampleBorrow<Borrowed> {
|
|||
/// [`Borrow::borrow`]: std::borrow::Borrow::borrow
|
||||
fn borrow(&self) -> &Borrowed;
|
||||
}
|
||||
impl<Borrowed> SampleBorrow<Borrowed> for Borrowed where Borrowed: SampleUniform {
|
||||
impl<Borrowed> SampleBorrow<Borrowed> for Borrowed
|
||||
where Borrowed: SampleUniform
|
||||
{
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &Borrowed { self }
|
||||
fn borrow(&self) -> &Borrowed {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed where Borrowed: SampleUniform {
|
||||
impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed
|
||||
where Borrowed: SampleUniform
|
||||
{
|
||||
#[inline(always)]
|
||||
fn borrow(&self) -> &Borrowed { *self }
|
||||
fn borrow(&self) -> &Borrowed {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -341,7 +350,7 @@ impl<'a, Borrowed> SampleBorrow<Borrowed> for &'a Borrowed where Borrowed: Sampl
|
|||
pub struct UniformInt<X> {
|
||||
low: X,
|
||||
range: X,
|
||||
z: X, // either ints_to_reject or zone depending on implementation
|
||||
z: X, // either ints_to_reject or zone depending on implementation
|
||||
}
|
||||
|
||||
macro_rules! uniform_int_impl {
|
||||
|
@ -361,8 +370,9 @@ macro_rules! uniform_int_impl {
|
|||
#[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
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = *low_b.borrow();
|
||||
let high = *high_b.borrow();
|
||||
|
@ -373,29 +383,31 @@ macro_rules! uniform_int_impl {
|
|||
#[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
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = *low_b.borrow();
|
||||
let high = *high_b.borrow();
|
||||
assert!(low <= high,
|
||||
"Uniform::new_inclusive called with `low > high`");
|
||||
assert!(
|
||||
low <= high,
|
||||
"Uniform::new_inclusive called with `low > high`"
|
||||
);
|
||||
let unsigned_max = ::core::$u_large::MAX;
|
||||
|
||||
let range = high.wrapping_sub(low).wrapping_add(1) as $unsigned;
|
||||
let ints_to_reject =
|
||||
if range > 0 {
|
||||
let range = $u_large::from(range);
|
||||
(unsigned_max - range + 1) % range
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let ints_to_reject = if range > 0 {
|
||||
let range = $u_large::from(range);
|
||||
(unsigned_max - range + 1) % range
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
UniformInt {
|
||||
low: low,
|
||||
// These are really $unsigned values, but store as $ty:
|
||||
range: range as $ty,
|
||||
z: ints_to_reject as $unsigned as $ty
|
||||
z: ints_to_reject as $unsigned as $ty,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,29 +429,27 @@ macro_rules! uniform_int_impl {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
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,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = *low_b.borrow();
|
||||
let high = *high_b.borrow();
|
||||
assert!(low < high,
|
||||
"UniformSampler::sample_single: low >= high");
|
||||
assert!(low < high, "UniformSampler::sample_single: low >= high");
|
||||
let range = high.wrapping_sub(low) 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
|
||||
// modulus for near-perfect branch prediction.
|
||||
let unsigned_max: $u_large = ::core::$u_large::MAX;
|
||||
let ints_to_reject = (unsigned_max - range + 1) % range;
|
||||
unsigned_max - ints_to_reject
|
||||
} else {
|
||||
// conservative but fast approximation. `- 1` is necessary to allow the
|
||||
// same comparison without bias.
|
||||
(range << range.leading_zeros()).wrapping_sub(1)
|
||||
};
|
||||
let zone = if ::core::$unsigned::MAX <= ::core::u16::MAX as $unsigned {
|
||||
// Using a modulus is faster than the approximation for
|
||||
// i8 and i16. I suppose we trade the cost of one
|
||||
// modulus for near-perfect branch prediction.
|
||||
let unsigned_max: $u_large = ::core::$u_large::MAX;
|
||||
let ints_to_reject = (unsigned_max - range + 1) % range;
|
||||
unsigned_max - ints_to_reject
|
||||
} else {
|
||||
// conservative but fast approximation. `- 1` is necessary to allow the
|
||||
// same comparison without bias.
|
||||
(range << range.leading_zeros()).wrapping_sub(1)
|
||||
};
|
||||
|
||||
loop {
|
||||
let v: $u_large = rng.gen();
|
||||
|
@ -450,7 +460,7 @@ macro_rules! uniform_int_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
uniform_int_impl! { i8, u8, u32 }
|
||||
|
@ -627,7 +637,7 @@ uniform_simd_int_impl! {
|
|||
///
|
||||
/// The floats are first converted to a value in the `[1, 2)` interval using a
|
||||
/// transmute-based method, and then mapped to the expected range with a
|
||||
/// multiply and addition. Values produced this way have what equals 22 bits of
|
||||
/// multiply and addition. Values produced this way have what equals 23 bits of
|
||||
/// random digits for an `f32`, and 52 for an `f64`.
|
||||
///
|
||||
/// [`new`]: UniformSampler::new
|
||||
|
@ -649,17 +659,20 @@ macro_rules! uniform_float_impl {
|
|||
type X = $ty;
|
||||
|
||||
fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = *low_b.borrow();
|
||||
let high = *high_b.borrow();
|
||||
assert!(low.all_lt(high),
|
||||
"Uniform::new called with `low >= high`");
|
||||
assert!(low.all_finite() && high.all_finite(),
|
||||
"Uniform::new called with non-finite boundaries");
|
||||
let max_rand = <$ty>::splat((::core::$u_scalar::MAX >> $bits_to_discard)
|
||||
.into_float_with_exponent(0) - 1.0);
|
||||
assert!(low.all_lt(high), "Uniform::new called with `low >= high`");
|
||||
assert!(
|
||||
low.all_finite() && high.all_finite(),
|
||||
"Uniform::new called with non-finite boundaries"
|
||||
);
|
||||
let max_rand = <$ty>::splat(
|
||||
(::core::$u_scalar::MAX >> $bits_to_discard).into_float_with_exponent(0) - 1.0,
|
||||
);
|
||||
|
||||
let mut scale = high - low;
|
||||
|
||||
|
@ -677,17 +690,23 @@ macro_rules! uniform_float_impl {
|
|||
}
|
||||
|
||||
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = *low_b.borrow();
|
||||
let high = *high_b.borrow();
|
||||
assert!(low.all_le(high),
|
||||
"Uniform::new_inclusive called with `low > high`");
|
||||
assert!(low.all_finite() && high.all_finite(),
|
||||
"Uniform::new_inclusive called with non-finite boundaries");
|
||||
let max_rand = <$ty>::splat((::core::$u_scalar::MAX >> $bits_to_discard)
|
||||
.into_float_with_exponent(0) - 1.0);
|
||||
assert!(
|
||||
low.all_le(high),
|
||||
"Uniform::new_inclusive called with `low > high`"
|
||||
);
|
||||
assert!(
|
||||
low.all_finite() && high.all_finite(),
|
||||
"Uniform::new_inclusive called with non-finite boundaries"
|
||||
);
|
||||
let max_rand = <$ty>::splat(
|
||||
(::core::$u_scalar::MAX >> $bits_to_discard).into_float_with_exponent(0) - 1.0,
|
||||
);
|
||||
|
||||
let mut scale = (high - low) / max_rand;
|
||||
|
||||
|
@ -706,8 +725,7 @@ macro_rules! uniform_float_impl {
|
|||
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
|
||||
// Generate a value in the range [1, 2)
|
||||
let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard)
|
||||
.into_float_with_exponent(0);
|
||||
let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard).into_float_with_exponent(0);
|
||||
|
||||
// Get a value in the range [0, 1) in order to avoid
|
||||
// overflowing into infinity when multiplying with scale
|
||||
|
@ -722,21 +740,23 @@ macro_rules! uniform_float_impl {
|
|||
}
|
||||
|
||||
#[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,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
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,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = *low_b.borrow();
|
||||
let high = *high_b.borrow();
|
||||
assert!(low.all_lt(high),
|
||||
"UniformSampler::sample_single: low >= high");
|
||||
assert!(
|
||||
low.all_lt(high),
|
||||
"UniformSampler::sample_single: low >= high"
|
||||
);
|
||||
let mut scale = high - low;
|
||||
|
||||
loop {
|
||||
// Generate a value in the range [1, 2)
|
||||
let value1_2 = (rng.gen::<$uty>() >> $bits_to_discard)
|
||||
.into_float_with_exponent(0);
|
||||
let value1_2 =
|
||||
(rng.gen::<$uty>() >> $bits_to_discard).into_float_with_exponent(0);
|
||||
|
||||
// Get a value in the range [0, 1) in order to avoid
|
||||
// overflowing into infinity when multiplying with scale
|
||||
|
@ -780,37 +800,38 @@ macro_rules! uniform_float_impl {
|
|||
// rare, so handle it here after the common case.
|
||||
let mask = !scale.finite_mask();
|
||||
if mask.any() {
|
||||
assert!(low.all_finite() && high.all_finite(),
|
||||
"Uniform::sample_single: low and high must be finite");
|
||||
assert!(
|
||||
low.all_finite() && high.all_finite(),
|
||||
"Uniform::sample_single: low and high must be finite"
|
||||
);
|
||||
scale = scale.decrease_masked(mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
uniform_float_impl! { f32, u32, f32, u32, 32 - 23 }
|
||||
uniform_float_impl! { f64, u64, f64, u64, 64 - 52 }
|
||||
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
uniform_float_impl! { f32x2, u32x2, f32, u32, 32 - 23 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
uniform_float_impl! { f32x4, u32x4, f32, u32, 32 - 23 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
uniform_float_impl! { f32x8, u32x8, f32, u32, 32 - 23 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
uniform_float_impl! { f32x16, u32x16, f32, u32, 32 - 23 }
|
||||
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
uniform_float_impl! { f64x2, u64x2, f64, u64, 64 - 52 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
uniform_float_impl! { f64x4, u64x4, f64, u64, 64 - 52 }
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
uniform_float_impl! { f64x8, u64x8, f64, u64, 64 - 52 }
|
||||
|
||||
|
||||
|
||||
/// The back-end implementing [`UniformSampler`] for `Duration`.
|
||||
///
|
||||
/// Unless you are implementing [`UniformSampler`] for your own types, this type
|
||||
|
@ -834,7 +855,7 @@ enum UniformDurationMode {
|
|||
max_secs: u64,
|
||||
max_nanos: u32,
|
||||
secs: Uniform<u64>,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
impl SampleUniform for Duration {
|
||||
|
@ -846,8 +867,9 @@ impl UniformSampler for UniformDuration {
|
|||
|
||||
#[inline]
|
||||
fn new<B1, B2>(low_b: B1, high_b: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = *low_b.borrow();
|
||||
let high = *high_b.borrow();
|
||||
|
@ -857,12 +879,16 @@ impl UniformSampler for UniformDuration {
|
|||
|
||||
#[inline]
|
||||
fn new_inclusive<B1, B2>(low_b: B1, high_b: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
let low = *low_b.borrow();
|
||||
let high = *high_b.borrow();
|
||||
assert!(low <= high, "Uniform::new_inclusive called with `low > high`");
|
||||
assert!(
|
||||
low <= high,
|
||||
"Uniform::new_inclusive called with `low > high`"
|
||||
);
|
||||
|
||||
let low_s = low.as_secs();
|
||||
let low_n = low.subsec_nanos();
|
||||
|
@ -916,7 +942,11 @@ impl UniformSampler for UniformDuration {
|
|||
let nanos = nanos.sample(rng);
|
||||
Duration::new(nanos / 1_000_000_000, (nanos % 1_000_000_000) as u32)
|
||||
}
|
||||
UniformDurationMode::Large { max_secs, max_nanos, secs } => {
|
||||
UniformDurationMode::Large {
|
||||
max_secs,
|
||||
max_nanos,
|
||||
secs,
|
||||
} => {
|
||||
// constant folding means this is at least as fast as `gen_range`
|
||||
let nano_range = Uniform::new(0, 1_000_000_000);
|
||||
loop {
|
||||
|
@ -959,12 +989,11 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_integers() {
|
||||
use core::{i8, i16, i32, i64, isize};
|
||||
use core::{u8, u16, u32, u64, usize};
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
use core::{i128, u128};
|
||||
#[cfg(not(target_os = "emscripten"))] use core::{i128, u128};
|
||||
use core::{i16, i32, i64, i8, isize};
|
||||
use core::{u16, u32, u64, u8, usize};
|
||||
|
||||
let mut rng = crate::test::rng(251);
|
||||
macro_rules! t {
|
||||
|
@ -1025,8 +1054,7 @@ mod tests {
|
|||
);)*
|
||||
}};
|
||||
}
|
||||
t!(i8, i16, i32, i64, isize,
|
||||
u8, u16, u32, u64, usize);
|
||||
t!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
t!(i128, u128);
|
||||
|
||||
|
@ -1044,29 +1072,29 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[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);
|
||||
let mut max_rng = StepRng::new(0xffff_ffff_ffff_ffff, 0);
|
||||
macro_rules! t {
|
||||
($ty:ty, $f_scalar:ident, $bits_shifted:expr) => {{
|
||||
let v: &[($f_scalar, $f_scalar)]=
|
||||
&[(0.0, 100.0),
|
||||
(-1e35, -1e25),
|
||||
(1e-35, 1e-25),
|
||||
(-1e35, 1e35),
|
||||
(<$f_scalar>::from_bits(0), <$f_scalar>::from_bits(3)),
|
||||
(-<$f_scalar>::from_bits(10), -<$f_scalar>::from_bits(1)),
|
||||
(-<$f_scalar>::from_bits(5), 0.0),
|
||||
(-<$f_scalar>::from_bits(7), -0.0),
|
||||
(10.0, ::core::$f_scalar::MAX),
|
||||
(-100.0, ::core::$f_scalar::MAX),
|
||||
(-::core::$f_scalar::MAX / 5.0, ::core::$f_scalar::MAX),
|
||||
(-::core::$f_scalar::MAX, ::core::$f_scalar::MAX / 5.0),
|
||||
(-::core::$f_scalar::MAX * 0.8, ::core::$f_scalar::MAX * 0.7),
|
||||
(-::core::$f_scalar::MAX, ::core::$f_scalar::MAX),
|
||||
];
|
||||
let v: &[($f_scalar, $f_scalar)] = &[
|
||||
(0.0, 100.0),
|
||||
(-1e35, -1e25),
|
||||
(1e-35, 1e-25),
|
||||
(-1e35, 1e35),
|
||||
(<$f_scalar>::from_bits(0), <$f_scalar>::from_bits(3)),
|
||||
(-<$f_scalar>::from_bits(10), -<$f_scalar>::from_bits(1)),
|
||||
(-<$f_scalar>::from_bits(5), 0.0),
|
||||
(-<$f_scalar>::from_bits(7), -0.0),
|
||||
(10.0, ::core::$f_scalar::MAX),
|
||||
(-100.0, ::core::$f_scalar::MAX),
|
||||
(-::core::$f_scalar::MAX / 5.0, ::core::$f_scalar::MAX),
|
||||
(-::core::$f_scalar::MAX, ::core::$f_scalar::MAX / 5.0),
|
||||
(-::core::$f_scalar::MAX * 0.8, ::core::$f_scalar::MAX * 0.7),
|
||||
(-::core::$f_scalar::MAX, ::core::$f_scalar::MAX),
|
||||
];
|
||||
for &(low_scalar, high_scalar) in v.iter() {
|
||||
for lane in 0..<$ty>::lanes() {
|
||||
let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar);
|
||||
|
@ -1082,7 +1110,10 @@ mod tests {
|
|||
assert!(low_scalar <= v && v < high_scalar);
|
||||
}
|
||||
|
||||
assert_eq!(rng.sample(Uniform::new_inclusive(low, low)).extract(lane), low_scalar);
|
||||
assert_eq!(
|
||||
rng.sample(Uniform::new_inclusive(low, low)).extract(lane),
|
||||
low_scalar
|
||||
);
|
||||
|
||||
assert_eq!(zero_rng.sample(my_uniform).extract(lane), low_scalar);
|
||||
assert_eq!(zero_rng.sample(my_incl_uniform).extract(lane), low_scalar);
|
||||
|
@ -1094,26 +1125,37 @@ mod tests {
|
|||
// since for those rounding might result in selecting high for a very
|
||||
// long time.
|
||||
if (high_scalar - low_scalar) > 0.0001 {
|
||||
let mut lowering_max_rng =
|
||||
StepRng::new(0xffff_ffff_ffff_ffff,
|
||||
(-1i64 << $bits_shifted) as u64);
|
||||
assert!(lowering_max_rng.gen_range(low, high).extract(lane) < high_scalar);
|
||||
let mut lowering_max_rng = StepRng::new(
|
||||
0xffff_ffff_ffff_ffff,
|
||||
(-1i64 << $bits_shifted) as u64,
|
||||
);
|
||||
assert!(
|
||||
lowering_max_rng.gen_range(low, high).extract(lane) < high_scalar
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(rng.sample(Uniform::new_inclusive(::core::$f_scalar::MAX,
|
||||
::core::$f_scalar::MAX)),
|
||||
::core::$f_scalar::MAX);
|
||||
assert_eq!(rng.sample(Uniform::new_inclusive(-::core::$f_scalar::MAX,
|
||||
-::core::$f_scalar::MAX)),
|
||||
-::core::$f_scalar::MAX);
|
||||
}}
|
||||
assert_eq!(
|
||||
rng.sample(Uniform::new_inclusive(
|
||||
::core::$f_scalar::MAX,
|
||||
::core::$f_scalar::MAX
|
||||
)),
|
||||
::core::$f_scalar::MAX
|
||||
);
|
||||
assert_eq!(
|
||||
rng.sample(Uniform::new_inclusive(
|
||||
-::core::$f_scalar::MAX,
|
||||
-::core::$f_scalar::MAX
|
||||
)),
|
||||
-::core::$f_scalar::MAX
|
||||
);
|
||||
}};
|
||||
}
|
||||
|
||||
t!(f32, f32, 32 - 23);
|
||||
t!(f64, f64, 64 - 52);
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
{
|
||||
t!(f32x2, f32, 32 - 23);
|
||||
t!(f32x4, f32, 32 - 23);
|
||||
|
@ -1126,13 +1168,14 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(all(feature="std",
|
||||
not(target_arch = "wasm32"),
|
||||
not(target_arch = "asmjs")))]
|
||||
#[cfg(not(miri))] // Miri does not support catching panics
|
||||
#[cfg(all(
|
||||
feature = "std",
|
||||
not(target_arch = "wasm32"),
|
||||
not(target_arch = "asmjs")
|
||||
))]
|
||||
fn test_float_assertions() {
|
||||
use std::panic::catch_unwind;
|
||||
use super::SampleUniform;
|
||||
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);
|
||||
|
@ -1140,20 +1183,23 @@ mod tests {
|
|||
|
||||
macro_rules! t {
|
||||
($ty:ident, $f_scalar:ident) => {{
|
||||
let v: &[($f_scalar, $f_scalar)] =
|
||||
&[(::std::$f_scalar::NAN, 0.0),
|
||||
(1.0, ::std::$f_scalar::NAN),
|
||||
(::std::$f_scalar::NAN, ::std::$f_scalar::NAN),
|
||||
(1.0, 0.5),
|
||||
(::std::$f_scalar::MAX, -::std::$f_scalar::MAX),
|
||||
(::std::$f_scalar::INFINITY, ::std::$f_scalar::INFINITY),
|
||||
(::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NEG_INFINITY),
|
||||
(::std::$f_scalar::NEG_INFINITY, 5.0),
|
||||
(5.0, ::std::$f_scalar::INFINITY),
|
||||
(::std::$f_scalar::NAN, ::std::$f_scalar::INFINITY),
|
||||
(::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NAN),
|
||||
(::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::INFINITY),
|
||||
];
|
||||
let v: &[($f_scalar, $f_scalar)] = &[
|
||||
(::std::$f_scalar::NAN, 0.0),
|
||||
(1.0, ::std::$f_scalar::NAN),
|
||||
(::std::$f_scalar::NAN, ::std::$f_scalar::NAN),
|
||||
(1.0, 0.5),
|
||||
(::std::$f_scalar::MAX, -::std::$f_scalar::MAX),
|
||||
(::std::$f_scalar::INFINITY, ::std::$f_scalar::INFINITY),
|
||||
(
|
||||
::std::$f_scalar::NEG_INFINITY,
|
||||
::std::$f_scalar::NEG_INFINITY,
|
||||
),
|
||||
(::std::$f_scalar::NEG_INFINITY, 5.0),
|
||||
(5.0, ::std::$f_scalar::INFINITY),
|
||||
(::std::$f_scalar::NAN, ::std::$f_scalar::INFINITY),
|
||||
(::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::NAN),
|
||||
(::std::$f_scalar::NEG_INFINITY, ::std::$f_scalar::INFINITY),
|
||||
];
|
||||
for &(low_scalar, high_scalar) in v.iter() {
|
||||
for lane in 0..<$ty>::lanes() {
|
||||
let low = <$ty>::splat(0.0 as $f_scalar).replace(lane, low_scalar);
|
||||
|
@ -1165,12 +1211,12 @@ mod tests {
|
|||
assert!(catch_unwind(|| Uniform::new(low, low)).is_err());
|
||||
}
|
||||
}
|
||||
}}
|
||||
}};
|
||||
}
|
||||
|
||||
t!(f32, f32);
|
||||
t!(f64, f64);
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
{
|
||||
t!(f32x2, f32);
|
||||
t!(f32x4, f32);
|
||||
|
@ -1184,18 +1230,21 @@ mod tests {
|
|||
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_durations() {
|
||||
#[cfg(feature = "std")]
|
||||
use std::time::Duration;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core::time::Duration;
|
||||
#[cfg(not(feature = "std"))] use core::time::Duration;
|
||||
#[cfg(feature = "std")] use std::time::Duration;
|
||||
|
||||
let mut rng = crate::test::rng(253);
|
||||
|
||||
let v = &[(Duration::new(10, 50000), Duration::new(100, 1234)),
|
||||
(Duration::new(0, 100), Duration::new(1, 50)),
|
||||
(Duration::new(0, 0), Duration::new(u64::max_value(), 999_999_999))];
|
||||
let v = &[
|
||||
(Duration::new(10, 50000), Duration::new(100, 1234)),
|
||||
(Duration::new(0, 100), Duration::new(1, 50)),
|
||||
(
|
||||
Duration::new(0, 0),
|
||||
Duration::new(u64::max_value(), 999_999_999),
|
||||
),
|
||||
];
|
||||
for &(low, high) in v.iter() {
|
||||
let my_uniform = Uniform::new(low, high);
|
||||
for _ in 0..1000 {
|
||||
|
@ -1207,7 +1256,9 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_custom_uniform() {
|
||||
use crate::distributions::uniform::{UniformSampler, UniformFloat, SampleUniform, SampleBorrow};
|
||||
use crate::distributions::uniform::{
|
||||
SampleBorrow, SampleUniform, UniformFloat, UniformSampler,
|
||||
};
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
||||
struct MyF32 {
|
||||
x: f32,
|
||||
|
@ -1216,27 +1267,34 @@ mod tests {
|
|||
struct UniformMyF32(UniformFloat<f32>);
|
||||
impl UniformSampler for UniformMyF32 {
|
||||
type X = MyF32;
|
||||
|
||||
fn new<B1, B2>(low: B1, high: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
UniformMyF32(UniformFloat::<f32>::new(low.borrow().x, high.borrow().x))
|
||||
}
|
||||
|
||||
fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self
|
||||
where B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized
|
||||
where
|
||||
B1: SampleBorrow<Self::X> + Sized,
|
||||
B2: SampleBorrow<Self::X> + Sized,
|
||||
{
|
||||
UniformSampler::new(low, high)
|
||||
}
|
||||
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Self::X {
|
||||
MyF32 { x: self.0.sample(rng) }
|
||||
MyF32 {
|
||||
x: self.0.sample(rng),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl SampleUniform for MyF32 {
|
||||
type Sampler = UniformMyF32;
|
||||
}
|
||||
|
||||
let (low, high) = (MyF32{ x: 17.0f32 }, MyF32{ x: 22.0f32 });
|
||||
let (low, high) = (MyF32 { x: 17.0f32 }, MyF32 { x: 22.0f32 });
|
||||
let uniform = Uniform::new(low, high);
|
||||
let mut rng = crate::test::rng(804);
|
||||
for _ in 0..100 {
|
||||
|
@ -1265,42 +1323,58 @@ mod tests {
|
|||
assert!(r.0.scale > 5.0);
|
||||
assert!(r.0.scale < 5.0 + 1e-14);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
fn test_samples<T: SampleUniform + Copy + core::fmt::Debug + PartialEq>(
|
||||
lb: T, ub: T, expected_single: &[T], expected_multiple: &[T]
|
||||
)
|
||||
where Uniform<T>: Distribution<T>
|
||||
{
|
||||
lb: T, ub: T, expected_single: &[T], expected_multiple: &[T],
|
||||
) where Uniform<T>: Distribution<T> {
|
||||
let mut rng = crate::test::rng(897);
|
||||
let mut buf = [lb; 3];
|
||||
|
||||
|
||||
for x in &mut buf {
|
||||
*x = T::Sampler::sample_single(lb, ub, &mut rng);
|
||||
}
|
||||
assert_eq!(&buf, expected_single);
|
||||
|
||||
|
||||
let distr = Uniform::new(lb, ub);
|
||||
for x in &mut buf {
|
||||
*x = rng.sample(&distr);
|
||||
}
|
||||
assert_eq!(&buf, expected_multiple);
|
||||
}
|
||||
|
||||
|
||||
// We test on a sub-set of types; possibly we should do more.
|
||||
// TODO: SIMD types
|
||||
|
||||
|
||||
test_samples(11u8, 219, &[17, 66, 214], &[181, 93, 165]);
|
||||
test_samples(11u32, 219, &[17, 66, 214], &[181, 93, 165]);
|
||||
|
||||
test_samples(0f32, 1e-2f32, &[0.0003070104, 0.0026630748, 0.00979833],
|
||||
&[0.008194133, 0.00398172, 0.007428536]);
|
||||
test_samples(-1e10f64, 1e10f64,
|
||||
&[-4673848682.871551, 6388267422.932352, 4857075081.198343],
|
||||
&[1173375212.1808167, 1917642852.109581, 2365076174.3153973]);
|
||||
|
||||
test_samples(Duration::new(2, 0), Duration::new(4, 0),
|
||||
&[Duration::new(2,532615131), Duration::new(3,638826742), Duration::new(3,485707508)], &[Duration::new(3,117337521), Duration::new(3,191764285), Duration::new(3,236507617)]);
|
||||
|
||||
test_samples(0f32, 1e-2f32, &[0.0003070104, 0.0026630748, 0.00979833], &[
|
||||
0.008194133,
|
||||
0.00398172,
|
||||
0.007428536,
|
||||
]);
|
||||
test_samples(
|
||||
-1e10f64,
|
||||
1e10f64,
|
||||
&[-4673848682.871551, 6388267422.932352, 4857075081.198343],
|
||||
&[1173375212.1808167, 1917642852.109581, 2365076174.3153973],
|
||||
);
|
||||
|
||||
test_samples(
|
||||
Duration::new(2, 0),
|
||||
Duration::new(4, 0),
|
||||
&[
|
||||
Duration::new(2, 532615131),
|
||||
Duration::new(3, 638826742),
|
||||
Duration::new(3, 485707508),
|
||||
],
|
||||
&[
|
||||
Duration::new(3, 117337521),
|
||||
Duration::new(3, 191764285),
|
||||
Duration::new(3, 236507617),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
#![allow(deprecated)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::{Distribution, Uniform};
|
||||
use crate::Rng;
|
||||
|
||||
/// Samples uniformly from the edge of the unit circle in two dimensions.
|
||||
///
|
||||
|
@ -20,7 +20,7 @@ use crate::distributions::{Distribution, Uniform};
|
|||
/// 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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UnitCircle;
|
||||
|
||||
|
@ -42,35 +42,36 @@ impl Distribution<[f64; 2]> for UnitCircle {
|
|||
loop {
|
||||
x1 = uniform.sample(rng);
|
||||
x2 = uniform.sample(rng);
|
||||
sum = x1*x1 + x2*x2;
|
||||
sum = x1 * x1 + x2 * x2;
|
||||
if sum < 1. {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let diff = x1*x1 - x2*x2;
|
||||
[diff / sum, 2.*x1*x2 / sum]
|
||||
let diff = x1 * x1 - x2 * x2;
|
||||
[diff / sum, 2. * x1 * x2 / sum]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::distributions::Distribution;
|
||||
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) => (
|
||||
($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));
|
||||
diff, $prec, $a, $b
|
||||
));
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -79,7 +80,7 @@ mod tests {
|
|||
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);
|
||||
assert_almost_eq!(x[0] * x[0] + x[1] * x[1], 1., 1e-15);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,15 +88,15 @@ mod tests {
|
|||
fn value_stability() {
|
||||
let mut rng = crate::test::rng(2);
|
||||
let expected = [
|
||||
[-0.9965658683520504, -0.08280380447614634],
|
||||
[-0.9790853270389644, -0.20345004884984505],
|
||||
[-0.8449189758898707, 0.5348943112253227],
|
||||
];
|
||||
[-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),
|
||||
];
|
||||
UnitCircle.sample(&mut rng),
|
||||
UnitCircle.sample(&mut rng),
|
||||
UnitCircle.sample(&mut rng),
|
||||
];
|
||||
assert_eq!(samples, expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
#![allow(deprecated)]
|
||||
#![allow(clippy::all)]
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::{Distribution, Uniform};
|
||||
use crate::Rng;
|
||||
|
||||
/// Samples uniformly from the surface of the unit sphere in three dimensions.
|
||||
///
|
||||
|
@ -19,7 +19,7 @@ use crate::distributions::{Distribution, Uniform};
|
|||
/// [^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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct UnitSphereSurface;
|
||||
|
||||
|
@ -37,35 +37,36 @@ impl Distribution<[f64; 3]> for UnitSphereSurface {
|
|||
let uniform = Uniform::new(-1., 1.);
|
||||
loop {
|
||||
let (x1, x2) = (uniform.sample(rng), uniform.sample(rng));
|
||||
let sum = x1*x1 + x2*x2;
|
||||
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];
|
||||
return [x1 * factor, x2 * factor, 1. - 2. * sum];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::distributions::Distribution;
|
||||
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) => (
|
||||
($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));
|
||||
diff, $prec, $a, $b
|
||||
));
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -74,7 +75,7 @@ mod tests {
|
|||
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);
|
||||
assert_almost_eq!(x[0] * x[0] + x[1] * x[1] + x[2] * x[2], 1., 1e-15);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,15 +83,15 @@ mod tests {
|
|||
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],
|
||||
];
|
||||
[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),
|
||||
];
|
||||
UnitSphereSurface.sample(&mut rng),
|
||||
UnitSphereSurface.sample(&mut rng),
|
||||
UnitSphereSurface.sample(&mut rng),
|
||||
];
|
||||
assert_eq!(samples, expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,9 @@
|
|||
|
||||
//! Math helper functions
|
||||
|
||||
#[cfg(feature="simd_support")]
|
||||
use packed_simd::*;
|
||||
#[cfg(feature="std")]
|
||||
use crate::distributions::ziggurat_tables;
|
||||
#[cfg(feature="std")]
|
||||
use crate::Rng;
|
||||
#[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> {
|
||||
|
@ -141,7 +138,7 @@ macro_rules! wmul_impl_usize {
|
|||
(high as usize, low as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
wmul_impl_usize! { u32 }
|
||||
|
@ -150,11 +147,9 @@ wmul_impl_usize! { u64 }
|
|||
|
||||
#[cfg(all(feature = "simd_support", feature = "nightly"))]
|
||||
mod simd_wmul {
|
||||
#[cfg(target_arch = "x86")]
|
||||
use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::arch::x86_64::*;
|
||||
use super::*;
|
||||
#[cfg(target_arch = "x86")] use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")] use core::arch::x86_64::*;
|
||||
|
||||
wmul_impl! {
|
||||
(u8x2, u16x2),
|
||||
|
@ -248,25 +243,35 @@ pub(crate) trait FloatSIMDUtils {
|
|||
|
||||
/// Implement functions available in std builds but missing from core primitives
|
||||
#[cfg(not(std))]
|
||||
pub(crate) trait Float : Sized {
|
||||
pub(crate) trait Float: Sized {
|
||||
fn is_nan(self) -> bool;
|
||||
fn is_infinite(self) -> bool;
|
||||
fn is_finite(self) -> bool;
|
||||
}
|
||||
|
||||
/// Implement functions on f32/f64 to give them APIs similar to SIMD types
|
||||
pub(crate) trait FloatAsSIMD : Sized {
|
||||
pub(crate) trait FloatAsSIMD: Sized {
|
||||
#[inline(always)]
|
||||
fn lanes() -> usize { 1 }
|
||||
fn lanes() -> usize {
|
||||
1
|
||||
}
|
||||
#[inline(always)]
|
||||
fn splat(scalar: Self) -> Self { scalar }
|
||||
fn splat(scalar: Self) -> Self {
|
||||
scalar
|
||||
}
|
||||
#[inline(always)]
|
||||
fn extract(self, index: usize) -> Self { debug_assert_eq!(index, 0); self }
|
||||
fn extract(self, index: usize) -> Self {
|
||||
debug_assert_eq!(index, 0);
|
||||
self
|
||||
}
|
||||
#[inline(always)]
|
||||
fn replace(self, index: usize, new_value: Self) -> Self { debug_assert_eq!(index, 0); new_value }
|
||||
fn replace(self, index: usize, new_value: Self) -> Self {
|
||||
debug_assert_eq!(index, 0);
|
||||
new_value
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait BoolAsSIMD : Sized {
|
||||
pub(crate) trait BoolAsSIMD: Sized {
|
||||
fn any(self) -> bool;
|
||||
fn all(self) -> bool;
|
||||
fn none(self) -> bool;
|
||||
|
@ -274,11 +279,19 @@ pub(crate) trait BoolAsSIMD : Sized {
|
|||
|
||||
impl BoolAsSIMD for bool {
|
||||
#[inline(always)]
|
||||
fn any(self) -> bool { self }
|
||||
fn any(self) -> bool {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn all(self) -> bool { self }
|
||||
fn all(self) -> bool {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn none(self) -> bool { !self }
|
||||
fn none(self) -> bool {
|
||||
!self
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! scalar_float_impl {
|
||||
|
@ -303,46 +316,80 @@ macro_rules! scalar_float_impl {
|
|||
|
||||
impl FloatSIMDUtils for $ty {
|
||||
type Mask = bool;
|
||||
type UInt = $uty;
|
||||
|
||||
#[inline(always)]
|
||||
fn all_lt(self, other: Self) -> bool { self < other }
|
||||
fn all_lt(self, other: Self) -> bool {
|
||||
self < other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn all_le(self, other: Self) -> bool { self <= other }
|
||||
fn all_le(self, other: Self) -> bool {
|
||||
self <= other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn all_finite(self) -> bool { self.is_finite() }
|
||||
fn all_finite(self) -> bool {
|
||||
self.is_finite()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn finite_mask(self) -> Self::Mask { self.is_finite() }
|
||||
fn finite_mask(self) -> Self::Mask {
|
||||
self.is_finite()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gt_mask(self, other: Self) -> Self::Mask { self > other }
|
||||
fn gt_mask(self, other: Self) -> Self::Mask {
|
||||
self > other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ge_mask(self, other: Self) -> Self::Mask { self >= other }
|
||||
fn ge_mask(self, other: Self) -> Self::Mask {
|
||||
self >= other
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn decrease_masked(self, mask: Self::Mask) -> Self {
|
||||
debug_assert!(mask, "At least one lane must be set");
|
||||
<$ty>::from_bits(self.to_bits() - 1)
|
||||
}
|
||||
type UInt = $uty;
|
||||
fn cast_from_int(i: Self::UInt) -> Self { i as $ty }
|
||||
|
||||
#[inline]
|
||||
fn cast_from_int(i: Self::UInt) -> Self {
|
||||
i as $ty
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatAsSIMD for $ty {}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
scalar_float_impl!(f32, u32);
|
||||
scalar_float_impl!(f64, u64);
|
||||
|
||||
|
||||
#[cfg(feature="simd_support")]
|
||||
#[cfg(feature = "simd_support")]
|
||||
macro_rules! simd_impl {
|
||||
($ty:ident, $f_scalar:ident, $mty:ident, $uty:ident) => {
|
||||
impl FloatSIMDUtils for $ty {
|
||||
type Mask = $mty;
|
||||
type UInt = $uty;
|
||||
|
||||
#[inline(always)]
|
||||
fn all_lt(self, other: Self) -> bool { self.lt(other).all() }
|
||||
fn all_lt(self, other: Self) -> bool {
|
||||
self.lt(other).all()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn all_le(self, other: Self) -> bool { self.le(other).all() }
|
||||
fn all_le(self, other: Self) -> bool {
|
||||
self.le(other).all()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn all_finite(self) -> bool { self.finite_mask().all() }
|
||||
fn all_finite(self) -> bool {
|
||||
self.finite_mask().all()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn finite_mask(self) -> Self::Mask {
|
||||
// This can possibly be done faster by checking bit patterns
|
||||
|
@ -350,10 +397,17 @@ macro_rules! simd_impl {
|
|||
let pos_inf = $ty::splat(::core::$f_scalar::INFINITY);
|
||||
self.gt(neg_inf) & self.lt(pos_inf)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gt_mask(self, other: Self) -> Self::Mask { self.gt(other) }
|
||||
fn gt_mask(self, other: Self) -> Self::Mask {
|
||||
self.gt(other)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ge_mask(self, other: Self) -> Self::Mask { self.ge(other) }
|
||||
fn ge_mask(self, other: Self) -> Self::Mask {
|
||||
self.ge(other)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn decrease_masked(self, mask: Self::Mask) -> Self {
|
||||
// Casting a mask into ints will produce all bits set for
|
||||
|
@ -365,11 +419,13 @@ macro_rules! simd_impl {
|
|||
debug_assert!(mask.any(), "At least one lane must be set");
|
||||
<$ty>::from_bits(<$uty>::from_bits(self) + <$uty>::from_bits(mask))
|
||||
}
|
||||
type UInt = $uty;
|
||||
|
||||
#[inline]
|
||||
fn cast_from_int(i: Self::UInt) -> Self { i.cast() }
|
||||
fn cast_from_int(i: Self::UInt) -> Self {
|
||||
i.cast()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature="simd_support")] simd_impl! { f32x2, f32, m32x2, u32x2 }
|
||||
|
@ -393,7 +449,7 @@ macro_rules! simd_impl {
|
|||
/// `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")]
|
||||
#[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] = [
|
||||
|
@ -438,16 +494,20 @@ pub fn log_gamma(x: f64) -> f64 {
|
|||
|
||||
// the perf improvement (25-50%) is definitely worth the extra code
|
||||
// size from force-inlining.
|
||||
#[cfg(feature="std")]
|
||||
#[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 {
|
||||
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.
|
||||
|
@ -466,12 +526,11 @@ pub fn ziggurat<R: Rng + ?Sized, P, Z>(
|
|||
(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)
|
||||
(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};
|
||||
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] {
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
//! The Weibull distribution.
|
||||
#![allow(deprecated)]
|
||||
|
||||
use crate::Rng;
|
||||
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")]
|
||||
#[deprecated(since = "0.7.0", note = "moved to rand_distr crate")]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Weibull {
|
||||
inv_shape: f64,
|
||||
|
@ -28,7 +28,10 @@ impl Weibull {
|
|||
/// `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 }
|
||||
Weibull {
|
||||
inv_shape: 1. / shape,
|
||||
scale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,8 +44,8 @@ impl Distribution<f64> for Weibull {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::distributions::Distribution;
|
||||
use super::Weibull;
|
||||
use crate::distributions::Distribution;
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
|
|
|
@ -2,17 +2,15 @@
|
|||
//! indices with probabilities proportional to a collection of weights.
|
||||
|
||||
use super::WeightedError;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use crate::alloc::vec::Vec;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use crate::alloc::vec;
|
||||
use core::fmt;
|
||||
use core::iter::Sum;
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
|
||||
#[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.
|
||||
///
|
||||
|
@ -192,9 +190,8 @@ impl<W: Weight> WeightedIndex<W> {
|
|||
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];
|
||||
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);
|
||||
|
@ -253,8 +250,7 @@ where
|
|||
}
|
||||
|
||||
impl<W: Weight> Clone for WeightedIndex<W>
|
||||
where
|
||||
Uniform<W>: Clone,
|
||||
where Uniform<W>: Clone
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
|
@ -370,7 +366,7 @@ mod test {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_weighted_index_f32() {
|
||||
test_weighted_index(f32::into);
|
||||
|
||||
|
@ -399,14 +395,14 @@ mod test {
|
|||
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[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(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_weighted_index_i128() {
|
||||
test_weighted_index(|x: i128| x as f64);
|
||||
|
||||
|
@ -422,13 +418,13 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_weighted_index_u8() {
|
||||
test_weighted_index(u8::into);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_weighted_index_i8() {
|
||||
test_weighted_index(i8::into);
|
||||
|
||||
|
@ -444,9 +440,7 @@ mod test {
|
|||
}
|
||||
|
||||
fn test_weighted_index<W: Weight, F: Fn(W) -> f64>(w_to_f64: F)
|
||||
where
|
||||
WeightedIndex<W>: fmt::Debug,
|
||||
{
|
||||
where WeightedIndex<W>: fmt::Debug {
|
||||
const NUM_WEIGHTS: u32 = 10;
|
||||
const ZERO_WEIGHT_INDEX: u32 = 3;
|
||||
const NUM_SAMPLES: u32 = 15000;
|
||||
|
@ -496,7 +490,7 @@ mod test {
|
|||
WeightedError::InvalidWeight
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
fn test_samples<W: Weight>(weights: Vec<W>, buf: &mut [usize], expected: &[usize]) {
|
||||
|
@ -508,10 +502,16 @@ mod test {
|
|||
}
|
||||
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]);
|
||||
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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
// 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
|
||||
|
@ -18,14 +18,14 @@
|
|||
|
||||
pub mod alias_method;
|
||||
|
||||
use crate::Rng;
|
||||
use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
|
||||
use crate::distributions::Distribution;
|
||||
use crate::distributions::uniform::{UniformSampler, SampleUniform, SampleBorrow};
|
||||
use crate::Rng;
|
||||
use core::cmp::PartialOrd;
|
||||
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;
|
||||
#[cfg(not(feature = "std"))] use crate::alloc::vec::Vec;
|
||||
|
||||
/// A distribution using weighted sampling to pick a discretely selected
|
||||
/// item.
|
||||
|
@ -98,16 +98,13 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
|
|||
///
|
||||
/// [`Uniform<X>`]: crate::distributions::uniform::Uniform
|
||||
pub fn new<I>(weights: I) -> Result<WeightedIndex<X>, WeightedError>
|
||||
where I: IntoIterator,
|
||||
I::Item: SampleBorrow<X>,
|
||||
X: for<'a> ::core::ops::AddAssign<&'a X> +
|
||||
Clone +
|
||||
Default {
|
||||
where
|
||||
I: IntoIterator,
|
||||
I::Item: SampleBorrow<X>,
|
||||
X: for<'a> ::core::ops::AddAssign<&'a X> + Clone + Default,
|
||||
{
|
||||
let mut iter = weights.into_iter();
|
||||
let mut total_weight: X = iter.next()
|
||||
.ok_or(WeightedError::NoItem)?
|
||||
.borrow()
|
||||
.clone();
|
||||
let mut total_weight: X = iter.next().ok_or(WeightedError::NoItem)?.borrow().clone();
|
||||
|
||||
let zero = <X as Default>::default();
|
||||
if total_weight < zero {
|
||||
|
@ -128,7 +125,11 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
|
|||
}
|
||||
let distr = X::Sampler::new(zero, total_weight.clone());
|
||||
|
||||
Ok(WeightedIndex { cumulative_weights: weights, total_weight, weight_distribution: distr })
|
||||
Ok(WeightedIndex {
|
||||
cumulative_weights: weights,
|
||||
total_weight,
|
||||
weight_distribution: distr,
|
||||
})
|
||||
}
|
||||
|
||||
/// Update a subset of weights, without changing the number of weights.
|
||||
|
@ -141,10 +142,10 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
|
|||
///
|
||||
/// In case of error, `self` is not modified.
|
||||
pub fn update_weights(&mut self, new_weights: &[(usize, &X)]) -> Result<(), WeightedError>
|
||||
where X: for<'a> ::core::ops::AddAssign<&'a X> +
|
||||
for<'a> ::core::ops::SubAssign<&'a X> +
|
||||
Clone +
|
||||
Default {
|
||||
where X: for<'a> ::core::ops::AddAssign<&'a X>
|
||||
+ for<'a> ::core::ops::SubAssign<&'a X>
|
||||
+ Clone
|
||||
+ Default {
|
||||
if new_weights.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -196,17 +197,17 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
|
|||
let mut cumulative_weight = if first_new_index > 0 {
|
||||
self.cumulative_weights[first_new_index - 1].clone()
|
||||
} else {
|
||||
zero.clone()
|
||||
zero.clone()
|
||||
};
|
||||
for i in first_new_index..self.cumulative_weights.len() {
|
||||
match next_new_weight {
|
||||
Some(&(j, w)) if i == j => {
|
||||
cumulative_weight += w;
|
||||
next_new_weight = iter.next();
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
let mut tmp = self.cumulative_weights[i].clone();
|
||||
tmp -= &prev_weight; // We know this is positive.
|
||||
tmp -= &prev_weight; // We know this is positive.
|
||||
cumulative_weight += &tmp;
|
||||
}
|
||||
}
|
||||
|
@ -221,14 +222,22 @@ impl<X: SampleUniform + PartialOrd> WeightedIndex<X> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<X> Distribution<usize> for WeightedIndex<X> where
|
||||
X: SampleUniform + PartialOrd {
|
||||
impl<X> Distribution<usize> for WeightedIndex<X>
|
||||
where X: SampleUniform + PartialOrd
|
||||
{
|
||||
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
|
||||
use ::core::cmp::Ordering;
|
||||
let chosen_weight = self.weight_distribution.sample(rng);
|
||||
// Find the first item which has a weight *higher* than the chosen weight.
|
||||
self.cumulative_weights.binary_search_by(
|
||||
|w| if *w <= chosen_weight { Ordering::Less } else { Ordering::Greater }).unwrap_err()
|
||||
self.cumulative_weights
|
||||
.binary_search_by(|w| {
|
||||
if *w <= chosen_weight {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
}
|
||||
})
|
||||
.unwrap_err()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +246,7 @@ mod test {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_weightedindex() {
|
||||
let mut r = crate::test::rng(700);
|
||||
const N_REPS: u32 = 5000;
|
||||
|
@ -282,28 +291,52 @@ mod test {
|
|||
for _ in 0..5 {
|
||||
assert_eq!(WeightedIndex::new(&[0, 1]).unwrap().sample(&mut r), 1);
|
||||
assert_eq!(WeightedIndex::new(&[1, 0]).unwrap().sample(&mut r), 0);
|
||||
assert_eq!(WeightedIndex::new(&[0, 0, 0, 0, 10, 0]).unwrap().sample(&mut r), 4);
|
||||
assert_eq!(
|
||||
WeightedIndex::new(&[0, 0, 0, 0, 10, 0])
|
||||
.unwrap()
|
||||
.sample(&mut r),
|
||||
4
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(WeightedIndex::new(&[10][0..0]).unwrap_err(), WeightedError::NoItem);
|
||||
assert_eq!(WeightedIndex::new(&[0]).unwrap_err(), WeightedError::AllWeightsZero);
|
||||
assert_eq!(WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(), WeightedError::InvalidWeight);
|
||||
assert_eq!(WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(), WeightedError::InvalidWeight);
|
||||
assert_eq!(WeightedIndex::new(&[-10]).unwrap_err(), WeightedError::InvalidWeight);
|
||||
assert_eq!(
|
||||
WeightedIndex::new(&[10][0..0]).unwrap_err(),
|
||||
WeightedError::NoItem
|
||||
);
|
||||
assert_eq!(
|
||||
WeightedIndex::new(&[0]).unwrap_err(),
|
||||
WeightedError::AllWeightsZero
|
||||
);
|
||||
assert_eq!(
|
||||
WeightedIndex::new(&[10, 20, -1, 30]).unwrap_err(),
|
||||
WeightedError::InvalidWeight
|
||||
);
|
||||
assert_eq!(
|
||||
WeightedIndex::new(&[-10, 20, 1, 30]).unwrap_err(),
|
||||
WeightedError::InvalidWeight
|
||||
);
|
||||
assert_eq!(
|
||||
WeightedIndex::new(&[-10]).unwrap_err(),
|
||||
WeightedError::InvalidWeight
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_weights() {
|
||||
let data = [
|
||||
(&[10u32, 2, 3, 4][..],
|
||||
&[(1, &100), (2, &4)][..], // positive change
|
||||
&[10, 100, 4, 4][..]),
|
||||
(&[1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7][..],
|
||||
&[(2, &1), (5, &1), (13, &100)][..], // negative change and last element
|
||||
&[1u32, 2, 1, 0, 5, 1, 7, 1, 2, 3, 4, 5, 6, 100][..]),
|
||||
(
|
||||
&[10u32, 2, 3, 4][..],
|
||||
&[(1, &100), (2, &4)][..], // positive change
|
||||
&[10, 100, 4, 4][..],
|
||||
),
|
||||
(
|
||||
&[1u32, 2, 3, 0, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7][..],
|
||||
&[(2, &1), (5, &1), (13, &100)][..], // negative change and last element
|
||||
&[1u32, 2, 1, 0, 5, 1, 7, 1, 2, 3, 4, 5, 6, 100][..],
|
||||
),
|
||||
];
|
||||
|
||||
for (weights, update, expected_weights) in data.into_iter() {
|
||||
for (weights, update, expected_weights) in data.iter() {
|
||||
let total_weight = weights.iter().sum::<u32>();
|
||||
let mut distr = WeightedIndex::new(weights.to_vec()).unwrap();
|
||||
assert_eq!(distr.total_weight, total_weight);
|
||||
|
@ -316,20 +349,15 @@ mod test {
|
|||
assert_eq!(distr.cumulative_weights, expected_distr.cumulative_weights);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn value_stability() {
|
||||
fn test_samples<X: SampleUniform + PartialOrd, I>
|
||||
(
|
||||
weights: I,
|
||||
buf: &mut [usize],
|
||||
expected: &[usize]
|
||||
)
|
||||
where I: IntoIterator,
|
||||
I::Item: SampleBorrow<X>,
|
||||
X: for<'a> ::core::ops::AddAssign<&'a X> +
|
||||
Clone +
|
||||
Default
|
||||
fn test_samples<X: SampleUniform + PartialOrd, I>(
|
||||
weights: I, buf: &mut [usize], expected: &[usize],
|
||||
) where
|
||||
I: IntoIterator,
|
||||
I::Item: SampleBorrow<X>,
|
||||
X: for<'a> ::core::ops::AddAssign<&'a X> + Clone + Default,
|
||||
{
|
||||
assert_eq!(buf.len(), expected.len());
|
||||
let distr = WeightedIndex::new(weights).unwrap();
|
||||
|
@ -339,11 +367,17 @@ mod test {
|
|||
}
|
||||
assert_eq!(buf, expected);
|
||||
}
|
||||
|
||||
|
||||
let mut buf = [0; 10];
|
||||
test_samples(&[1i32,1,1,1,1,1,1,1,1], &mut buf, &[0, 6, 2, 6, 3, 4, 7, 8, 2, 5]);
|
||||
test_samples(&[0.7f32, 0.1, 0.1, 0.1], &mut buf, &[0, 0, 0, 1, 0, 0, 2, 3, 0, 0]);
|
||||
test_samples(&[1.0f64, 0.999, 0.998, 0.997], &mut buf, &[2, 2, 1, 3, 2, 1, 3, 3, 2, 1]);
|
||||
test_samples(&[1i32, 1, 1, 1, 1, 1, 1, 1, 1], &mut buf, &[
|
||||
0, 6, 2, 6, 3, 4, 7, 8, 2, 5,
|
||||
]);
|
||||
test_samples(&[0.7f32, 0.1, 0.1, 0.1], &mut buf, &[
|
||||
0, 0, 0, 1, 0, 0, 2, 3, 0, 0,
|
||||
]);
|
||||
test_samples(&[1.0f64, 0.999, 0.998, 0.997], &mut buf, &[
|
||||
2, 2, 1, 3, 2, 1, 3, 3, 2, 1,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -359,34 +393,21 @@ pub enum WeightedError {
|
|||
|
||||
/// All items in the provided weight collection are zero.
|
||||
AllWeightsZero,
|
||||
|
||||
|
||||
/// Too many weights are provided (length greater than `u32::MAX`)
|
||||
TooMany,
|
||||
}
|
||||
|
||||
impl WeightedError {
|
||||
fn msg(&self) -> &str {
|
||||
match *self {
|
||||
WeightedError::NoItem => "No weights provided.",
|
||||
WeightedError::InvalidWeight => "A weight is invalid.",
|
||||
WeightedError::AllWeightsZero => "All weights are zero.",
|
||||
WeightedError::TooMany => "Too many weights (hit u32::MAX)",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="std")]
|
||||
impl ::std::error::Error for WeightedError {
|
||||
fn description(&self) -> &str {
|
||||
self.msg()
|
||||
}
|
||||
fn cause(&self) -> Option<&dyn (::std::error::Error)> {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "std")]
|
||||
impl ::std::error::Error for WeightedError {}
|
||||
|
||||
impl fmt::Display for WeightedError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.msg())
|
||||
match *self {
|
||||
WeightedError::NoItem => write!(f, "No weights provided."),
|
||||
WeightedError::InvalidWeight => write!(f, "A weight is invalid."),
|
||||
WeightedError::AllWeightsZero => write!(f, "All weights are zero."),
|
||||
WeightedError::TooMany => write!(f, "Too many weights (hit u32::MAX)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
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,
|
||||
|
@ -78,6 +79,7 @@ pub static ZIG_NORM_X: [f64; 257] =
|
|||
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,
|
||||
|
@ -145,6 +147,7 @@ pub static ZIG_NORM_F: [f64; 257] =
|
|||
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,
|
||||
|
@ -211,6 +214,7 @@ pub static ZIG_EXP_X: [f64; 257] =
|
|||
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,
|
||||
|
|
|
@ -40,22 +40,23 @@
|
|||
//! For the user guide and futher documentation, please read
|
||||
//! [The Rust Rand Book](https://rust-random.github.io/book).
|
||||
|
||||
|
||||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
|
||||
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://rust-random.github.io/rand/")]
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
|
||||
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://rust-random.github.io/rand/"
|
||||
)]
|
||||
#![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))]
|
||||
#![allow(
|
||||
clippy::excessive_precision,
|
||||
clippy::unreadable_literal,
|
||||
clippy::float_cmp
|
||||
)]
|
||||
|
||||
#![cfg_attr(not(feature="std"), no_std)]
|
||||
#![cfg_attr(all(feature="simd_support", feature="nightly"), feature(stdsimd))]
|
||||
|
||||
#![allow(clippy::excessive_precision, clippy::unreadable_literal, clippy::float_cmp)]
|
||||
|
||||
#[cfg(all(feature="alloc", not(feature="std")))]
|
||||
extern crate alloc;
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc;
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! trace { ($($x:tt)*) => (
|
||||
|
@ -89,10 +90,10 @@ macro_rules! error { ($($x:tt)*) => (
|
|||
) }
|
||||
|
||||
// Re-exports from rand_core
|
||||
pub use rand_core::{RngCore, CryptoRng, SeedableRng, Error};
|
||||
pub use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
|
||||
|
||||
// Public exports
|
||||
#[cfg(feature="std")] pub use crate::rngs::thread::thread_rng;
|
||||
#[cfg(feature = "std")] pub use crate::rngs::thread::thread_rng;
|
||||
|
||||
// Public modules
|
||||
pub mod distributions;
|
||||
|
@ -101,10 +102,10 @@ pub mod rngs;
|
|||
pub mod seq;
|
||||
|
||||
|
||||
use core::{mem, slice};
|
||||
use core::num::Wrapping;
|
||||
use crate::distributions::uniform::{SampleBorrow, SampleUniform, UniformSampler};
|
||||
use crate::distributions::{Distribution, Standard};
|
||||
use crate::distributions::uniform::{SampleUniform, UniformSampler, SampleBorrow};
|
||||
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.
|
||||
|
@ -268,7 +269,10 @@ pub trait Rng: RngCore {
|
|||
/// }
|
||||
/// ```
|
||||
fn sample_iter<T, D>(self, distr: D) -> distributions::DistIter<D, Self, T>
|
||||
where D: Distribution<T>, Self: Sized {
|
||||
where
|
||||
D: Distribution<T>,
|
||||
Self: Sized,
|
||||
{
|
||||
distr.sample_iter(self)
|
||||
}
|
||||
|
||||
|
@ -468,9 +472,11 @@ macro_rules! impl_as_byte_slice {
|
|||
}
|
||||
|
||||
impl_as_byte_slice!(u16, u32, u64, usize,);
|
||||
#[cfg(not(target_os = "emscripten"))] impl_as_byte_slice!(u128);
|
||||
#[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);
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
impl_as_byte_slice!(i128);
|
||||
|
||||
macro_rules! impl_as_byte_slice_arrays {
|
||||
($n:expr,) => {};
|
||||
|
@ -495,6 +501,7 @@ macro_rules! impl_as_byte_slice_arrays {
|
|||
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,);
|
||||
|
||||
|
@ -540,7 +547,7 @@ impl_as_byte_slice_arrays!(!div 4096, N,N,N,N,N,N,N,);
|
|||
/// ```
|
||||
///
|
||||
/// [`Standard`]: distributions::Standard
|
||||
#[cfg(feature="std")]
|
||||
#[cfg(feature = "std")]
|
||||
#[inline]
|
||||
pub fn random<T>() -> T
|
||||
where Standard: Distribution<T> {
|
||||
|
@ -549,9 +556,9 @@ where Standard: Distribution<T> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::rngs::mock::StepRng;
|
||||
use super::*;
|
||||
#[cfg(all(not(feature="std"), feature="alloc"))] use alloc::boxed::Box;
|
||||
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 {
|
||||
|
@ -566,8 +573,7 @@ mod test {
|
|||
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];
|
||||
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];
|
||||
|
@ -584,7 +590,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_fill() {
|
||||
let x = 9041086907909331047; // a random u64
|
||||
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.
|
||||
|
@ -670,7 +676,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature="alloc")]
|
||||
#[cfg(feature = "alloc")]
|
||||
fn test_rng_boxed_trait() {
|
||||
use crate::distributions::{Distribution, Standard};
|
||||
let rng = rng(110);
|
||||
|
@ -682,22 +688,22 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature="std")]
|
||||
#[cfg(feature = "std")]
|
||||
fn test_random() {
|
||||
// not sure how to test this aside from just getting some values
|
||||
let _n : usize = random();
|
||||
let _f : f32 = random();
|
||||
let _o : Option<Option<i8>> = random();
|
||||
let _many : ((),
|
||||
(usize,
|
||||
isize,
|
||||
Option<(u32, (bool,))>),
|
||||
(u8, i8, u16, i16, u32, i32, u64, i64),
|
||||
(f32, (f64, (f64,)))) = random();
|
||||
let _n: usize = random();
|
||||
let _f: f32 = random();
|
||||
let _o: Option<Option<i8>> = random();
|
||||
let _many: (
|
||||
(),
|
||||
(usize, isize, Option<(u32, (bool,))>),
|
||||
(u8, i8, u16, i16, u32, i32, u64, i64),
|
||||
(f32, (f64, (f64,))),
|
||||
) = random();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_gen_ratio_average() {
|
||||
const NUM: u32 = 3;
|
||||
const DENOM: u32 = 10;
|
||||
|
@ -711,7 +717,7 @@ mod test {
|
|||
}
|
||||
}
|
||||
// Have Binomial(N, NUM/DENOM) distribution
|
||||
let expected = (NUM * N) / DENOM; // exact integer
|
||||
let expected = (NUM * N) / DENOM; // exact integer
|
||||
assert!(((sum - expected) as i32).abs() < 500);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,10 +19,15 @@
|
|||
//! ```
|
||||
|
||||
#[doc(no_inline)] pub use crate::distributions::Distribution;
|
||||
#[cfg(feature = "small_rng")]
|
||||
#[doc(no_inline)]
|
||||
pub use crate::rngs::SmallRng;
|
||||
#[doc(no_inline)] pub use crate::rngs::StdRng;
|
||||
#[cfg(feature="small_rng")]
|
||||
#[doc(no_inline)] pub use crate::rngs::SmallRng;
|
||||
#[doc(no_inline)] #[cfg(feature="std")] pub use crate::rngs::ThreadRng;
|
||||
#[doc(no_inline)] pub use crate::{Rng, RngCore, CryptoRng, SeedableRng};
|
||||
#[doc(no_inline)] #[cfg(feature="std")] pub use crate::{random, thread_rng};
|
||||
#[doc(no_inline)] pub use crate::seq::{SliceRandom, IteratorRandom};
|
||||
#[doc(no_inline)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use crate::rngs::ThreadRng;
|
||||
#[doc(no_inline)] pub use crate::seq::{IteratorRandom, SliceRandom};
|
||||
#[doc(no_inline)]
|
||||
#[cfg(feature = "std")]
|
||||
pub use crate::{random, thread_rng};
|
||||
#[doc(no_inline)] pub use crate::{CryptoRng, Rng, RngCore, SeedableRng};
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
//! Wrappers / adapters forming RNGs
|
||||
|
||||
#[cfg(feature="std")] mod read;
|
||||
#[cfg(feature = "std")] mod read;
|
||||
mod reseeding;
|
||||
|
||||
#[cfg(feature="std")] pub use self::read::{ReadRng, ReadError};
|
||||
#[cfg(feature = "std")] pub use self::read::{ReadError, ReadRng};
|
||||
pub use self::reseeding::ReseedingRng;
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
|
||||
//! A wrapper around any Read to treat it as an RNG.
|
||||
|
||||
use std::io::Read;
|
||||
use std::fmt;
|
||||
use std::io::Read;
|
||||
|
||||
use rand_core::{RngCore, Error, impls};
|
||||
use rand_core::{impls, Error, RngCore};
|
||||
|
||||
|
||||
/// An RNG that reads random bytes straight from any type supporting
|
||||
|
@ -45,15 +45,13 @@ use rand_core::{RngCore, Error, impls};
|
|||
/// [`try_fill_bytes`]: RngCore::try_fill_bytes
|
||||
#[derive(Debug)]
|
||||
pub struct ReadRng<R> {
|
||||
reader: R
|
||||
reader: R,
|
||||
}
|
||||
|
||||
impl<R: Read> ReadRng<R> {
|
||||
/// Create a new `ReadRng` from a `Read`.
|
||||
pub fn new(r: R) -> ReadRng<R> {
|
||||
ReadRng {
|
||||
reader: r
|
||||
}
|
||||
ReadRng { reader: r }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,14 +65,22 @@ impl<R: Read> RngCore for ReadRng<R> {
|
|||
}
|
||||
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||
self.try_fill_bytes(dest).unwrap_or_else(|err|
|
||||
panic!("reading random bytes from Read implementation failed; error: {}", err));
|
||||
self.try_fill_bytes(dest).unwrap_or_else(|err| {
|
||||
panic!(
|
||||
"reading random bytes from Read implementation failed; error: {}",
|
||||
err
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
|
||||
if dest.is_empty() { return Ok(()); }
|
||||
if dest.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
// Use `std::io::read_exact`, which retries on `ErrorKind::Interrupted`.
|
||||
self.reader.read_exact(dest).map_err(|e| Error::new(ReadError(e)))
|
||||
self.reader
|
||||
.read_exact(dest)
|
||||
.map_err(|e| Error::new(ReadError(e)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,6 +109,7 @@ mod test {
|
|||
#[test]
|
||||
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];
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
use core::mem::size_of;
|
||||
|
||||
use rand_core::{RngCore, CryptoRng, SeedableRng, Error};
|
||||
use rand_core::block::{BlockRngCore, BlockRng};
|
||||
use rand_core::block::{BlockRng, BlockRngCore};
|
||||
use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
|
||||
|
||||
/// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the
|
||||
/// ability to reseed it.
|
||||
|
@ -77,12 +77,14 @@ use rand_core::block::{BlockRngCore, BlockRng};
|
|||
/// [`reseed()`]: ReseedingRng::reseed
|
||||
#[derive(Debug)]
|
||||
pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>)
|
||||
where R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore;
|
||||
where
|
||||
R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore;
|
||||
|
||||
impl<R, Rsdr> ReseedingRng<R, Rsdr>
|
||||
where R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore
|
||||
where
|
||||
R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore,
|
||||
{
|
||||
/// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG
|
||||
/// to use as reseeder.
|
||||
|
@ -103,8 +105,9 @@ where R: BlockRngCore + SeedableRng,
|
|||
// TODO: this should be implemented for any type where the inner type
|
||||
// implements RngCore, but we can't specify that because ReseedingCore is private
|
||||
impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr>
|
||||
where R: BlockRngCore<Item = u32> + SeedableRng,
|
||||
<R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>
|
||||
where
|
||||
R: BlockRngCore<Item = u32> + SeedableRng,
|
||||
<R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn next_u32(&mut self) -> u32 {
|
||||
|
@ -126,8 +129,9 @@ where R: BlockRngCore<Item = u32> + SeedableRng,
|
|||
}
|
||||
|
||||
impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr>
|
||||
where R: BlockRngCore + SeedableRng + Clone,
|
||||
Rsdr: RngCore + Clone
|
||||
where
|
||||
R: BlockRngCore + SeedableRng + Clone,
|
||||
Rsdr: RngCore + Clone,
|
||||
{
|
||||
fn clone(&self) -> ReseedingRng<R, Rsdr> {
|
||||
// Recreating `BlockRng` seems easier than cloning it and resetting
|
||||
|
@ -137,8 +141,11 @@ where R: BlockRngCore + SeedableRng + Clone,
|
|||
}
|
||||
|
||||
impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr>
|
||||
where R: BlockRngCore + SeedableRng + CryptoRng,
|
||||
Rsdr: RngCore + CryptoRng {}
|
||||
where
|
||||
R: BlockRngCore + SeedableRng + CryptoRng,
|
||||
Rsdr: RngCore + CryptoRng,
|
||||
{
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ReseedingCore<R, Rsdr> {
|
||||
|
@ -150,16 +157,16 @@ struct ReseedingCore<R, Rsdr> {
|
|||
}
|
||||
|
||||
impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr>
|
||||
where R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore
|
||||
where
|
||||
R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore,
|
||||
{
|
||||
type Item = <R as BlockRngCore>::Item;
|
||||
type Results = <R as BlockRngCore>::Results;
|
||||
|
||||
fn generate(&mut self, results: &mut Self::Results) {
|
||||
let global_fork_counter = fork::get_fork_counter();
|
||||
if self.bytes_until_reseed <= 0 ||
|
||||
self.is_forked(global_fork_counter) {
|
||||
if self.bytes_until_reseed <= 0 || self.is_forked(global_fork_counter) {
|
||||
// We get better performance by not calling only `reseed` here
|
||||
// and continuing with the rest of the function, but by directly
|
||||
// returning from a non-inlined function.
|
||||
|
@ -172,8 +179,9 @@ where R: BlockRngCore + SeedableRng,
|
|||
}
|
||||
|
||||
impl<R, Rsdr> ReseedingCore<R, Rsdr>
|
||||
where R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore
|
||||
where
|
||||
R: BlockRngCore + SeedableRng,
|
||||
Rsdr: RngCore,
|
||||
{
|
||||
/// Create a new `ReseedingCore`.
|
||||
fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
|
||||
|
@ -184,10 +192,13 @@ where R: BlockRngCore + SeedableRng,
|
|||
// current hardware, we just clamp to that value.
|
||||
// Also we set a threshold of 0, which indicates no limit, to that
|
||||
// value.
|
||||
let threshold =
|
||||
if threshold == 0 { MAX }
|
||||
else if threshold <= MAX as u64 { threshold as i64 }
|
||||
else { MAX };
|
||||
let threshold = if threshold == 0 {
|
||||
MAX
|
||||
} else if threshold <= MAX as u64 {
|
||||
threshold as i64
|
||||
} else {
|
||||
MAX
|
||||
};
|
||||
|
||||
ReseedingCore {
|
||||
inner: rng,
|
||||
|
@ -221,19 +232,17 @@ where R: BlockRngCore + SeedableRng,
|
|||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn reseed_and_generate(&mut self,
|
||||
results: &mut <Self as BlockRngCore>::Results,
|
||||
global_fork_counter: usize)
|
||||
{
|
||||
#![allow(clippy::if_same_then_else)] // false positive
|
||||
fn reseed_and_generate(
|
||||
&mut self, results: &mut <Self as BlockRngCore>::Results, global_fork_counter: usize,
|
||||
) {
|
||||
#![allow(clippy::if_same_then_else)] // false positive
|
||||
if self.is_forked(global_fork_counter) {
|
||||
info!("Fork detected, reseeding RNG");
|
||||
} else {
|
||||
trace!("Reseeding RNG (periodic reseed)");
|
||||
}
|
||||
|
||||
let num_bytes =
|
||||
results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>();
|
||||
let num_bytes = results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>();
|
||||
|
||||
if let Err(e) = self.reseed() {
|
||||
warn!("Reseeding RNG failed: {}", e);
|
||||
|
@ -247,8 +256,9 @@ where R: BlockRngCore + SeedableRng,
|
|||
}
|
||||
|
||||
impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr>
|
||||
where R: BlockRngCore + SeedableRng + Clone,
|
||||
Rsdr: RngCore + Clone
|
||||
where
|
||||
R: BlockRngCore + SeedableRng + Clone,
|
||||
Rsdr: RngCore + Clone,
|
||||
{
|
||||
fn clone(&self) -> ReseedingCore<R, Rsdr> {
|
||||
ReseedingCore {
|
||||
|
@ -262,15 +272,17 @@ where R: BlockRngCore + SeedableRng + Clone,
|
|||
}
|
||||
|
||||
impl<R, Rsdr> CryptoRng for ReseedingCore<R, Rsdr>
|
||||
where R: BlockRngCore + SeedableRng + CryptoRng,
|
||||
Rsdr: RngCore + CryptoRng {}
|
||||
where
|
||||
R: BlockRngCore + SeedableRng + CryptoRng,
|
||||
Rsdr: RngCore + CryptoRng,
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#[cfg(all(unix, not(target_os="emscripten")))]
|
||||
#[cfg(all(unix, feature = "std", not(target_os = "emscripten")))]
|
||||
mod fork {
|
||||
use core::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
|
||||
#[allow(deprecated)] // Required for compatibility with Rust < 1.24.
|
||||
use core::sync::atomic::{ATOMIC_USIZE_INIT, ATOMIC_BOOL_INIT};
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Once;
|
||||
|
||||
// Fork protection
|
||||
//
|
||||
|
@ -284,43 +296,41 @@ mod fork {
|
|||
// don't update `fork_counter`, so a reseed is attempted as soon as
|
||||
// possible.
|
||||
|
||||
#[allow(deprecated)]
|
||||
static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
pub fn get_fork_counter() -> usize {
|
||||
RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
static FORK_HANDLER_REGISTERED: AtomicBool = ATOMIC_BOOL_INIT;
|
||||
|
||||
extern fn fork_handler() {
|
||||
extern "C" fn fork_handler() {
|
||||
// Note: fetch_add is defined to wrap on overflow
|
||||
// (which is what we want).
|
||||
RESEEDING_RNG_FORK_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn register_fork_handler() {
|
||||
if !FORK_HANDLER_REGISTERED.load(Ordering::Relaxed) {
|
||||
unsafe { libc::pthread_atfork(None, None, Some(fork_handler)) };
|
||||
FORK_HANDLER_REGISTERED.store(true, Ordering::Relaxed);
|
||||
}
|
||||
static REGISTER: Once = Once::new();
|
||||
REGISTER.call_once(|| unsafe {
|
||||
libc::pthread_atfork(None, None, Some(fork_handler));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(unix, not(target_os="emscripten"))))]
|
||||
#[cfg(not(all(unix, feature = "std", not(target_os = "emscripten"))))]
|
||||
mod fork {
|
||||
pub fn get_fork_counter() -> usize { 0 }
|
||||
pub fn get_fork_counter() -> usize {
|
||||
0
|
||||
}
|
||||
pub fn register_fork_handler() {}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{Rng, SeedableRng};
|
||||
use crate::rngs::std::Core;
|
||||
use crate::rngs::mock::StepRng;
|
||||
use super::ReseedingRng;
|
||||
use crate::rngs::mock::StepRng;
|
||||
use crate::rngs::std::Core;
|
||||
use crate::{Rng, SeedableRng};
|
||||
|
||||
#[test]
|
||||
fn test_reseeding() {
|
||||
|
@ -346,10 +356,12 @@ mod test {
|
|||
fn test_clone_reseeding() {
|
||||
let mut zero = StepRng::new(0, 0);
|
||||
let rng = Core::from_rng(&mut zero).unwrap();
|
||||
let mut rng1 = ReseedingRng::new(rng, 32*4, zero);
|
||||
let mut rng1 = ReseedingRng::new(rng, 32 * 4, zero);
|
||||
|
||||
let first: u32 = rng1.gen();
|
||||
for _ in 0..10 { let _ = rng1.gen::<u32>(); }
|
||||
for _ in 0..10 {
|
||||
let _ = rng1.gen::<u32>();
|
||||
}
|
||||
|
||||
let mut rng2 = rng1.clone();
|
||||
assert_eq!(first, rng2.gen::<u32>());
|
||||
|
|
|
@ -8,19 +8,19 @@
|
|||
|
||||
//! Entropy generator, or wrapper around external generators
|
||||
|
||||
#![allow(deprecated)] // whole module is deprecated
|
||||
#![allow(deprecated)] // whole module is deprecated
|
||||
|
||||
use rand_core::{RngCore, CryptoRng, Error};
|
||||
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")]
|
||||
#[deprecated(since = "0.7.0", note = "use rngs::OsRng instead")]
|
||||
pub struct EntropyRng {
|
||||
source: OsRng,
|
||||
}
|
||||
|
@ -71,6 +71,6 @@ mod 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
|
||||
assert!(n >= 2); // p(failure) approx 1e-7
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,18 @@
|
|||
|
||||
//! Mock random number generator
|
||||
|
||||
use rand_core::{RngCore, Error, impls};
|
||||
use rand_core::{impls, Error, RngCore};
|
||||
|
||||
/// A simple implementation of `RngCore` for testing purposes.
|
||||
///
|
||||
///
|
||||
/// This generates an arithmetic sequence (i.e. adds a constant each step)
|
||||
/// over a `u64` number, using wrapping arithmetic. If the increment is 0
|
||||
/// the generator yields a constant.
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use rand::Rng;
|
||||
/// use rand::rngs::mock::StepRng;
|
||||
///
|
||||
///
|
||||
/// let mut my_rng = StepRng::new(2, 1);
|
||||
/// let sample: [u64; 3] = my_rng.gen();
|
||||
/// assert_eq!(sample, [2, 3, 4]);
|
||||
|
@ -34,7 +34,10 @@ impl StepRng {
|
|||
/// Create a `StepRng`, yielding an arithmetic sequence starting with
|
||||
/// `initial` and incremented by `increment` each time.
|
||||
pub fn new(initial: u64, increment: u64) -> Self {
|
||||
StepRng { v: initial, a: increment }
|
||||
StepRng {
|
||||
v: initial,
|
||||
a: increment,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,13 +84,11 @@
|
|||
//! Some suggestions are: [`rand_chacha`], [`rand_pcg`], [`rand_xoshiro`].
|
||||
//! A full list can be found by searching for crates with the [`rng` tag].
|
||||
//!
|
||||
//! [`SmallRng`]: rngs::SmallRng
|
||||
//! [`StdRng`]: rngs::StdRng
|
||||
//! [`OsRng`]: rngs::OsRng
|
||||
//! [`ThreadRng`]: rngs::ThreadRng
|
||||
//! [`mock::StepRng`]: rngs::mock::StepRng
|
||||
//! [`adapter::ReadRng`]: rngs::adapter::ReadRng
|
||||
//! [`adapter::ReseedingRng`]: rngs::adapter::ReseedingRng
|
||||
//! [`Rng`]: crate::Rng
|
||||
//! [`RngCore`]: crate::RngCore
|
||||
//! [`CryptoRng`]: crate::CryptoRng
|
||||
//! [`SeedableRng`]: crate::SeedableRng
|
||||
//! [`thread_rng`]: crate::thread_rng
|
||||
//! [`rdrand`]: https://crates.io/crates/rdrand
|
||||
//! [`rand_jitter`]: https://crates.io/crates/rand_jitter
|
||||
//! [`rand_chacha`]: https://crates.io/crates/rand_chacha
|
||||
|
@ -100,20 +98,19 @@
|
|||
|
||||
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;
|
||||
#[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;
|
||||
#[cfg(feature = "std")] pub(crate) mod thread;
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature="std")] pub use self::entropy::EntropyRng;
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::entropy::EntropyRng;
|
||||
|
||||
#[cfg(feature="small_rng")]
|
||||
pub use self::small::SmallRng;
|
||||
#[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")] pub use self::thread::ThreadRng;
|
||||
|
||||
#[cfg(feature="getrandom")] pub use rand_core::OsRng;
|
||||
#[cfg(feature = "getrandom")] pub use rand_core::OsRng;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
//! A small fast RNG
|
||||
|
||||
use rand_core::{RngCore, SeedableRng, Error};
|
||||
use rand_core::{Error, RngCore, SeedableRng};
|
||||
|
||||
#[cfg(all(not(target_os = "emscripten"), target_pointer_width = "64"))]
|
||||
type Rng = rand_pcg::Pcg64Mcg;
|
||||
|
@ -56,7 +56,6 @@ type Rng = rand_pcg::Pcg32;
|
|||
/// efficient:
|
||||
///
|
||||
/// ```
|
||||
/// use std::iter;
|
||||
/// use rand::{SeedableRng, thread_rng};
|
||||
/// use rand::rngs::SmallRng;
|
||||
///
|
||||
|
@ -65,9 +64,8 @@ type Rng = rand_pcg::Pcg32;
|
|||
/// let mut thread_rng = thread_rng();
|
||||
/// // Create small, cheap to initialize and fast RNGs with random seeds.
|
||||
/// // One can generally assume this won't fail.
|
||||
/// let rngs: Vec<SmallRng> = iter::repeat(())
|
||||
/// .map(|()| SmallRng::from_rng(&mut thread_rng).unwrap())
|
||||
/// .take(10)
|
||||
/// let rngs: Vec<SmallRng> = (0..10)
|
||||
/// .map(|_| SmallRng::from_rng(&mut thread_rng).unwrap())
|
||||
/// .collect();
|
||||
/// ```
|
||||
///
|
||||
|
|
|
@ -8,22 +8,21 @@
|
|||
|
||||
//! The standard RNG
|
||||
|
||||
use crate::{RngCore, CryptoRng, Error, SeedableRng};
|
||||
use crate::{CryptoRng, Error, RngCore, SeedableRng};
|
||||
|
||||
#[cfg(all(any(test, feature = "std"), target_os = "emscripten"))]
|
||||
pub(crate) use rand_hc::Hc128Core as Core;
|
||||
#[cfg(all(any(test, feature = "std"), not(target_os = "emscripten")))]
|
||||
pub(crate) use rand_chacha::ChaCha20Core as Core;
|
||||
#[cfg(all(any(test, feature = "std"), target_os = "emscripten"))]
|
||||
pub(crate) use rand_hc::Hc128Core as Core;
|
||||
|
||||
#[cfg(target_os = "emscripten")] use rand_hc::Hc128Rng as Rng;
|
||||
#[cfg(not(target_os = "emscripten"))] use rand_chacha::ChaCha20Rng 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 either 20 or 12
|
||||
/// rounds (see the `stdrng_*` feature flags, documented in the README).
|
||||
/// 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.
|
||||
///
|
||||
|
@ -77,21 +76,22 @@ impl CryptoRng for StdRng {}
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{RngCore, SeedableRng};
|
||||
use crate::rngs::StdRng;
|
||||
use crate::{RngCore, SeedableRng};
|
||||
|
||||
#[test]
|
||||
fn test_stdrng_construction() {
|
||||
// Test value-stability of StdRng. This is expected to break any time
|
||||
// the algorithm is changed.
|
||||
#[rustfmt::skip]
|
||||
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")))]
|
||||
#[cfg(any(feature = "stdrng_strong", not(feature = "stdrng_fast")))]
|
||||
let target = [3950704604716924505, 5573172343717151650];
|
||||
#[cfg(all(not(feature="stdrng_strong"), feature="stdrng_fast"))]
|
||||
#[cfg(all(not(feature = "stdrng_strong"), feature = "stdrng_fast"))]
|
||||
let target = [10719222850664546238, 14064965282130556830];
|
||||
|
||||
|
||||
let mut rng0 = StdRng::from_seed(seed);
|
||||
let x0 = rng0.next_u64();
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
use std::cell::UnsafeCell;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use crate::{RngCore, CryptoRng, SeedableRng, Error};
|
||||
use super::std::Core;
|
||||
use crate::rngs::adapter::ReseedingRng;
|
||||
use crate::rngs::OsRng;
|
||||
use super::std::Core;
|
||||
use crate::{CryptoRng, Error, RngCore, SeedableRng};
|
||||
|
||||
// Rationale for using `UnsafeCell` in `ThreadRng`:
|
||||
//
|
||||
|
|
|
@ -8,15 +8,18 @@
|
|||
|
||||
//! Low-level API for sampling indices
|
||||
|
||||
#[cfg(feature="alloc")] use core::slice;
|
||||
#[cfg(feature = "alloc")] use core::slice;
|
||||
|
||||
#[cfg(feature="std")] use std::vec;
|
||||
#[cfg(all(feature="alloc", not(feature="std")))] use crate::alloc::vec::{self, Vec};
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
use crate::alloc::vec::{self, Vec};
|
||||
#[cfg(feature = "std")] use std::vec;
|
||||
// BTreeMap is not as fast in tests, but better than nothing.
|
||||
#[cfg(feature="std")] use std::collections::{HashSet};
|
||||
#[cfg(all(feature="alloc", not(feature="std")))] use crate::alloc::collections::BTreeSet;
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||
use crate::alloc::collections::BTreeSet;
|
||||
#[cfg(feature = "std")] use std::collections::HashSet;
|
||||
|
||||
#[cfg(feature="alloc")] use crate::distributions::{Distribution, Uniform, uniform::SampleUniform};
|
||||
#[cfg(feature = "alloc")]
|
||||
use crate::distributions::{uniform::SampleUniform, Distribution, Uniform};
|
||||
use crate::Rng;
|
||||
|
||||
/// A vector of indices.
|
||||
|
@ -24,8 +27,10 @@ use crate::Rng;
|
|||
/// Multiple internal representations are possible.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum IndexVec {
|
||||
#[doc(hidden)] U32(Vec<u32>),
|
||||
#[doc(hidden)] USize(Vec<usize>),
|
||||
#[doc(hidden)]
|
||||
U32(Vec<u32>),
|
||||
#[doc(hidden)]
|
||||
USize(Vec<usize>),
|
||||
}
|
||||
|
||||
impl IndexVec {
|
||||
|
@ -93,10 +98,12 @@ impl PartialEq for IndexVec {
|
|||
match (self, other) {
|
||||
(&U32(ref v1), &U32(ref v2)) => v1 == v2,
|
||||
(&USize(ref v1), &USize(ref v2)) => v1 == v2,
|
||||
(&U32(ref v1), &USize(ref v2)) => (v1.len() == v2.len())
|
||||
&& (v1.iter().zip(v2.iter()).all(|(x, y)| *x as usize == *y)),
|
||||
(&USize(ref v1), &U32(ref v2)) => (v1.len() == v2.len())
|
||||
&& (v1.iter().zip(v2.iter()).all(|(x, y)| *x == *y as usize)),
|
||||
(&U32(ref v1), &USize(ref v2)) => {
|
||||
(v1.len() == v2.len()) && (v1.iter().zip(v2.iter()).all(|(x, y)| *x as usize == *y))
|
||||
}
|
||||
(&USize(ref v1), &U32(ref v2)) => {
|
||||
(v1.len() == v2.len()) && (v1.iter().zip(v2.iter()).all(|(x, y)| *x == *y as usize))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,12 +125,15 @@ impl From<Vec<usize>> for IndexVec {
|
|||
/// Return type of `IndexVec::iter`.
|
||||
#[derive(Debug)]
|
||||
pub enum IndexVecIter<'a> {
|
||||
#[doc(hidden)] U32(slice::Iter<'a, u32>),
|
||||
#[doc(hidden)] USize(slice::Iter<'a, usize>),
|
||||
#[doc(hidden)]
|
||||
U32(slice::Iter<'a, u32>),
|
||||
#[doc(hidden)]
|
||||
USize(slice::Iter<'a, usize>),
|
||||
}
|
||||
|
||||
impl<'a> Iterator for IndexVecIter<'a> {
|
||||
type Item = usize;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<usize> {
|
||||
use self::IndexVecIter::*;
|
||||
|
@ -147,8 +157,10 @@ impl<'a> ExactSizeIterator for IndexVecIter<'a> {}
|
|||
/// Return type of `IndexVec::into_iter`.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum IndexVecIntoIter {
|
||||
#[doc(hidden)] U32(vec::IntoIter<u32>),
|
||||
#[doc(hidden)] USize(vec::IntoIter<usize>),
|
||||
#[doc(hidden)]
|
||||
U32(vec::IntoIter<u32>),
|
||||
#[doc(hidden)]
|
||||
USize(vec::IntoIter<usize>),
|
||||
}
|
||||
|
||||
impl Iterator for IndexVecIntoIter {
|
||||
|
@ -216,7 +228,7 @@ where R: Rng + ?Sized {
|
|||
// We do some calculations with f32. Accuracy is not very important.
|
||||
|
||||
if amount < 163 {
|
||||
const C: [[f32; 2]; 2] = [[1.6, 8.0/45.0], [10.0, 70.0/9.0]];
|
||||
const C: [[f32; 2]; 2] = [[1.6, 8.0 / 45.0], [10.0, 70.0 / 9.0]];
|
||||
let j = if length < 500_000 { 0 } else { 1 };
|
||||
let amount_fp = amount as f32;
|
||||
let m4 = C[0][j] * amount_fp;
|
||||
|
@ -227,7 +239,7 @@ where R: Rng + ?Sized {
|
|||
sample_floyd(rng, length, amount)
|
||||
}
|
||||
} else {
|
||||
const C: [f32; 2] = [270.0, 330.0/9.0];
|
||||
const C: [f32; 2] = [270.0, 330.0 / 9.0];
|
||||
let j = if length < 500_000 { 0 } else { 1 };
|
||||
if (length as f32) < C[j] * (amount as f32) {
|
||||
sample_inplace(rng, length, amount)
|
||||
|
@ -252,7 +264,7 @@ where R: Rng + ?Sized {
|
|||
|
||||
debug_assert!(amount <= length);
|
||||
let mut indices = Vec::with_capacity(amount as usize);
|
||||
for j in length - amount .. length {
|
||||
for j in length - amount..length {
|
||||
let t = rng.gen_range(0, j + 1);
|
||||
if floyd_shuffle {
|
||||
if let Some(pos) = indices.iter().position(|&x| x == t) {
|
||||
|
@ -306,12 +318,26 @@ trait UInt: Copy + PartialOrd + Ord + PartialEq + Eq + SampleUniform + core::has
|
|||
fn as_usize(self) -> usize;
|
||||
}
|
||||
impl UInt for u32 {
|
||||
#[inline] fn zero() -> Self { 0 }
|
||||
#[inline] fn as_usize(self) -> usize { self as usize }
|
||||
#[inline]
|
||||
fn zero() -> Self {
|
||||
0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_usize(self) -> usize {
|
||||
self as usize
|
||||
}
|
||||
}
|
||||
impl UInt for usize {
|
||||
#[inline] fn zero() -> Self { 0 }
|
||||
#[inline] fn as_usize(self) -> usize { self }
|
||||
#[inline]
|
||||
fn zero() -> Self {
|
||||
0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_usize(self) -> usize {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Randomly sample exactly `amount` indices from `0..length`, using rejection
|
||||
|
@ -320,14 +346,19 @@ impl UInt for usize {
|
|||
/// Since `amount <<< length` there is a low chance of a random sample in
|
||||
/// `0..length` being a duplicate. We test for duplicates and resample where
|
||||
/// necessary. The algorithm is `O(amount)` time and memory.
|
||||
///
|
||||
///
|
||||
/// This function is generic over X primarily so that results are value-stable
|
||||
/// over 32-bit and 64-bit platforms.
|
||||
fn sample_rejection<X: UInt, R>(rng: &mut R, length: X, amount: X) -> IndexVec
|
||||
where R: Rng + ?Sized, IndexVec: From<Vec<X>> {
|
||||
where
|
||||
R: Rng + ?Sized,
|
||||
IndexVec: From<Vec<X>>,
|
||||
{
|
||||
debug_assert!(amount < length);
|
||||
#[cfg(feature="std")] let mut cache = HashSet::with_capacity(amount.as_usize());
|
||||
#[cfg(not(feature="std"))] let mut cache = BTreeSet::new();
|
||||
#[cfg(feature = "std")]
|
||||
let mut cache = HashSet::with_capacity(amount.as_usize());
|
||||
#[cfg(not(feature = "std"))]
|
||||
let mut cache = BTreeSet::new();
|
||||
let distr = Uniform::new(X::zero(), length);
|
||||
let mut indices = Vec::with_capacity(amount.as_usize());
|
||||
for _ in 0..amount.as_usize() {
|
||||
|
@ -344,9 +375,9 @@ where R: Rng + ?Sized, IndexVec: From<Vec<X>> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[cfg(feature="std")] use std::vec;
|
||||
#[cfg(all(feature="alloc", not(feature="std")))] use crate::alloc::vec;
|
||||
use super::*;
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec;
|
||||
#[cfg(feature = "std")] use std::vec;
|
||||
|
||||
#[test]
|
||||
fn test_sample_boundaries() {
|
||||
|
@ -363,17 +394,15 @@ mod test {
|
|||
assert_eq!(sample_floyd(&mut r, 1, 1).into_vec(), vec![0]);
|
||||
|
||||
// These algorithms should be fast with big numbers. Test average.
|
||||
let sum: usize = sample_rejection(&mut r, 1 << 25, 10u32)
|
||||
.into_iter().sum();
|
||||
let sum: usize = sample_rejection(&mut r, 1 << 25, 10u32).into_iter().sum();
|
||||
assert!(1 << 25 < sum && sum < (1 << 25) * 25);
|
||||
|
||||
let sum: usize = sample_floyd(&mut r, 1 << 25, 10)
|
||||
.into_iter().sum();
|
||||
let sum: usize = sample_floyd(&mut r, 1 << 25, 10).into_iter().sum();
|
||||
assert!(1 << 25 < sum && sum < (1 << 25) * 25);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_sample_alg() {
|
||||
let seed_rng = crate::test::rng;
|
||||
|
||||
|
@ -393,14 +422,14 @@ mod test {
|
|||
assert!(v1 != v3);
|
||||
|
||||
// A large length and small amount should use Floyd
|
||||
let (length, amount): (usize, usize) = (1<<20, 50);
|
||||
let (length, amount): (usize, usize) = (1 << 20, 50);
|
||||
let v1 = sample(&mut seed_rng(421), length, amount);
|
||||
let v2 = sample_floyd(&mut seed_rng(421), length as u32, amount as u32);
|
||||
assert!(v1.iter().all(|e| e < length));
|
||||
assert_eq!(v1, v2);
|
||||
|
||||
// A large length and larger amount should use cache
|
||||
let (length, amount): (usize, usize) = (1<<20, 600);
|
||||
let (length, amount): (usize, usize) = (1 << 20, 600);
|
||||
let v1 = sample(&mut seed_rng(422), length, amount);
|
||||
let v2 = sample_rejection(&mut seed_rng(422), length as u32, amount as u32);
|
||||
assert!(v1.iter().all(|e| e < length));
|
||||
|
|
|
@ -7,42 +7,43 @@
|
|||
// except according to those terms.
|
||||
|
||||
//! Sequence-related functionality
|
||||
//!
|
||||
//!
|
||||
//! This module provides:
|
||||
//!
|
||||
//! * [`seq::SliceRandom`] slice sampling and mutation
|
||||
//! * [`seq::IteratorRandom`] iterator sampling
|
||||
//! * [`seq::index::sample`] low-level API to choose multiple indices from
|
||||
//!
|
||||
//! * [`SliceRandom`] slice sampling and mutation
|
||||
//! * [`IteratorRandom`] iterator sampling
|
||||
//! * [`index::sample`] low-level API to choose multiple indices from
|
||||
//! `0..length`
|
||||
//!
|
||||
//!
|
||||
//! Also see:
|
||||
//!
|
||||
//! * [`distributions::weighted`] module which provides implementations of
|
||||
//! weighted index sampling.
|
||||
//!
|
||||
//!
|
||||
//! * [`crate::distributions::weighted`] module which provides
|
||||
//! implementations of 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")] pub mod index;
|
||||
|
||||
#[cfg(feature="alloc")] use core::ops::Index;
|
||||
#[cfg(feature = "alloc")] use core::ops::Index;
|
||||
|
||||
#[cfg(all(feature="alloc", not(feature="std")))] use crate::alloc::vec::Vec;
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))] use crate::alloc::vec::Vec;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use crate::distributions::uniform::{SampleBorrow, SampleUniform};
|
||||
#[cfg(feature = "alloc")] use crate::distributions::WeightedError;
|
||||
use crate::Rng;
|
||||
#[cfg(feature="alloc")] use crate::distributions::WeightedError;
|
||||
#[cfg(feature="alloc")] use crate::distributions::uniform::{SampleUniform, SampleBorrow};
|
||||
|
||||
/// Extension trait on slices, providing random mutation and sampling methods.
|
||||
///
|
||||
///
|
||||
/// This trait is implemented on all `[T]` slice types, providing several
|
||||
/// methods for choosing and shuffling elements. You must `use` this trait:
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use rand::seq::SliceRandom;
|
||||
///
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut rng = rand::thread_rng();
|
||||
/// let mut bytes = "Hello, random!".to_string().into_bytes();
|
||||
|
@ -61,7 +62,7 @@ pub trait SliceRandom {
|
|||
|
||||
/// Returns a reference to one random element of the slice, or `None` if the
|
||||
/// slice is empty.
|
||||
///
|
||||
///
|
||||
/// For slices, complexity is `O(1)`.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -115,7 +116,7 @@ pub trait SliceRandom {
|
|||
|
||||
/// Similar to [`choose`], but where the likelihood of each outcome may be
|
||||
/// specified.
|
||||
///
|
||||
///
|
||||
/// 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)`.
|
||||
|
@ -152,7 +153,7 @@ pub trait SliceRandom {
|
|||
|
||||
/// Similar to [`choose_mut`], but where the likelihood of each outcome may
|
||||
/// be specified.
|
||||
///
|
||||
///
|
||||
/// 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)`.
|
||||
|
@ -220,13 +221,13 @@ pub trait SliceRandom {
|
|||
}
|
||||
|
||||
/// Extension trait on iterators, providing random sampling methods.
|
||||
///
|
||||
///
|
||||
/// This trait is implemented on all sized iterators, providing methods for
|
||||
/// choosing one or more elements. You must `use` this trait:
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use rand::seq::IteratorRandom;
|
||||
///
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut rng = rand::thread_rng();
|
||||
///
|
||||
|
@ -240,7 +241,7 @@ pub trait SliceRandom {
|
|||
/// ```
|
||||
pub trait IteratorRandom: Iterator + Sized {
|
||||
/// Choose one element at random from the iterator.
|
||||
///
|
||||
///
|
||||
/// Returns `None` if and only if the iterator is empty.
|
||||
///
|
||||
/// This method uses [`Iterator::size_hint`] for optimisation. With an
|
||||
|
@ -248,7 +249,7 @@ pub trait IteratorRandom: Iterator + Sized {
|
|||
/// this method can offer `O(1)` performance. Where no size hint is
|
||||
/// 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.
|
||||
fn choose<R>(mut self, rng: &mut R) -> Option<Self::Item>
|
||||
|
@ -258,7 +259,11 @@ pub trait IteratorRandom: Iterator + Sized {
|
|||
let mut result = None;
|
||||
|
||||
if upper == Some(lower) {
|
||||
return if lower == 0 { None } else { self.nth(gen_index(rng, lower)) };
|
||||
return if lower == 0 {
|
||||
None
|
||||
} else {
|
||||
self.nth(gen_index(rng, lower))
|
||||
};
|
||||
}
|
||||
|
||||
// Continue until the iterator is exhausted
|
||||
|
@ -478,7 +483,7 @@ impl<I> IteratorRandom for I where I: Iterator + Sized {}
|
|||
|
||||
|
||||
/// An iterator over multiple slice elements.
|
||||
///
|
||||
///
|
||||
/// This struct is created by
|
||||
/// [`SliceRandom::choose_multiple`](trait.SliceRandom.html#tymethod.choose_multiple).
|
||||
#[cfg(feature = "alloc")]
|
||||
|
@ -530,13 +535,14 @@ fn gen_index<R: Rng + ?Sized>(rng: &mut R, ubound: usize) -> usize {
|
|||
mod test {
|
||||
use super::*;
|
||||
#[cfg(feature = "alloc")] use crate::Rng;
|
||||
#[cfg(all(feature="alloc", not(feature="std")))]
|
||||
use alloc::vec::Vec;
|
||||
#[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::Vec;
|
||||
|
||||
#[test]
|
||||
fn test_slice_choose() {
|
||||
let mut r = crate::test::rng(107);
|
||||
let chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n'];
|
||||
let chars = [
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
];
|
||||
let mut chosen = [0i32; 14];
|
||||
// The below all use a binomial distribution with n=1000, p=1/14.
|
||||
// binocdf(40, 1000, 1/14) ~= 2e-5; 1-binocdf(106, ..) ~= 2e-5
|
||||
|
@ -567,6 +573,7 @@ mod test {
|
|||
}
|
||||
impl<I: Iterator + Clone> Iterator for UnhintedIterator<I> {
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
@ -581,18 +588,25 @@ mod test {
|
|||
}
|
||||
impl<I: ExactSizeIterator + Iterator + Clone> Iterator for ChunkHintedIterator<I> {
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.chunk_remaining == 0 {
|
||||
self.chunk_remaining = ::core::cmp::min(self.chunk_size,
|
||||
self.iter.len());
|
||||
self.chunk_remaining = ::core::cmp::min(self.chunk_size, self.iter.len());
|
||||
}
|
||||
self.chunk_remaining = self.chunk_remaining.saturating_sub(1);
|
||||
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.chunk_remaining,
|
||||
if self.hint_total_size { Some(self.iter.len()) } else { None })
|
||||
(
|
||||
self.chunk_remaining,
|
||||
if self.hint_total_size {
|
||||
Some(self.iter.len())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,20 +618,28 @@ mod test {
|
|||
}
|
||||
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>) {
|
||||
(::core::cmp::min(self.iter.len(), self.window_size),
|
||||
if self.hint_total_size { Some(self.iter.len()) } else { None })
|
||||
(
|
||||
::core::cmp::min(self.iter.len(), self.window_size),
|
||||
if self.hint_total_size {
|
||||
Some(self.iter.len())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_iterator_choose() {
|
||||
let r = &mut crate::test::rng(109);
|
||||
fn test_iter<R: Rng + ?Sized, Iter: Iterator<Item=usize> + Clone>(r: &mut R, iter: Iter) {
|
||||
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(r).unwrap();
|
||||
|
@ -627,7 +649,11 @@ mod test {
|
|||
// 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);
|
||||
assert!(
|
||||
72 < *count && *count < 154,
|
||||
"count not close to 1000/9: {}",
|
||||
count
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -636,17 +662,35 @@ mod test {
|
|||
#[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 });
|
||||
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);
|
||||
assert_eq!(UnhintedIterator { iter: 0..0 }.choose(r), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_shuffle() {
|
||||
let mut r = crate::test::rng(108);
|
||||
let empty: &mut [isize] = &mut [];
|
||||
|
@ -694,15 +738,15 @@ mod test {
|
|||
assert!(352 <= *count && *count <= 483, "count: {}", count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_partial_shuffle() {
|
||||
let mut r = crate::test::rng(118);
|
||||
|
||||
|
||||
let mut empty: [u32; 0] = [];
|
||||
let res = empty.partial_shuffle(&mut r, 10);
|
||||
assert_eq!((res.0.len(), res.1.len()), (0, 0));
|
||||
|
||||
|
||||
let mut v = [1, 2, 3, 4, 5];
|
||||
let res = v.partial_shuffle(&mut r, 2);
|
||||
assert_eq!((res.0.len(), res.1.len()), (2, 3));
|
||||
|
@ -727,14 +771,14 @@ mod test {
|
|||
// no randomization happens when amount >= len
|
||||
assert_eq!(large_sample, vals.iter().collect::<Vec<_>>());
|
||||
|
||||
assert!(small_sample.iter().all(|e| {
|
||||
**e >= min_val && **e <= max_val
|
||||
}));
|
||||
assert!(small_sample
|
||||
.iter()
|
||||
.all(|e| { **e >= min_val && **e <= max_val }));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[cfg_attr(miri, ignore)] // Miri is too slow
|
||||
fn test_weighted() {
|
||||
let mut r = crate::test::rng(406);
|
||||
const N_REPS: u32 = 3000;
|
||||
|
@ -782,10 +826,25 @@ mod test {
|
|||
|
||||
// Check error cases
|
||||
let empty_slice = &mut [10][0..0];
|
||||
assert_eq!(empty_slice.choose_weighted(&mut r, |_| 1), Err(WeightedError::NoItem));
|
||||
assert_eq!(empty_slice.choose_weighted_mut(&mut r, |_| 1), Err(WeightedError::NoItem));
|
||||
assert_eq!(['x'].choose_weighted_mut(&mut r, |_| 0), Err(WeightedError::AllWeightsZero));
|
||||
assert_eq!([0, -1].choose_weighted_mut(&mut r, |x| *x), Err(WeightedError::InvalidWeight));
|
||||
assert_eq!([-1, 0].choose_weighted_mut(&mut r, |x| *x), Err(WeightedError::InvalidWeight));
|
||||
assert_eq!(
|
||||
empty_slice.choose_weighted(&mut r, |_| 1),
|
||||
Err(WeightedError::NoItem)
|
||||
);
|
||||
assert_eq!(
|
||||
empty_slice.choose_weighted_mut(&mut r, |_| 1),
|
||||
Err(WeightedError::NoItem)
|
||||
);
|
||||
assert_eq!(
|
||||
['x'].choose_weighted_mut(&mut r, |_| 0),
|
||||
Err(WeightedError::AllWeightsZero)
|
||||
);
|
||||
assert_eq!(
|
||||
[0, -1].choose_weighted_mut(&mut r, |x| *x),
|
||||
Err(WeightedError::InvalidWeight)
|
||||
);
|
||||
assert_eq!(
|
||||
[-1, 0].choose_weighted_mut(&mut r, |x| *x),
|
||||
Err(WeightedError::InvalidWeight)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"files":{"CHANGELOG.md":"f4db0c6a73be9b43000a8cbd77b357db26b6021d24b8820170510ca533e4788d","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"16dfc2309bba54b46dde69b242dc2af8096104076f34748b808259dbf181d2cd","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"5b6d753b28e14cc08a25aaa56c941f038c0e3d8e340129492c3e2824401bdd66","src/chacha.rs":"b16ca319071ac4e83474e6a6c749d0ab7ef1df47a3bdba72bb8b566d9d4f598d","src/lib.rs":"01a10cc42b0a0d61308f0e5706c8a02f345271b744fc5f238e36b4a61127ad6e"},"package":"03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"}
|
||||
{"files":{"CHANGELOG.md":"cfa5a57b442ab6da8e03c4b5f82e63a74c97a999edfbf7841646d4612f399206","COPYRIGHT":"90eb64f0279b0d9432accfa6023ff803bc4965212383697eee27a0f426d5f8d5","Cargo.toml":"254d87eb2174bd4375fba1b2818d7295d558721582af12f600241da250250310","LICENSE-APACHE":"aaff376532ea30a0cd5330b9502ad4a4c8bf769c539c87ffe78819d188a18ebf","LICENSE-MIT":"209fbbe0ad52d9235e37badf9cadfe4dbdc87203179c0899e738b39ade42177b","README.md":"5b6d753b28e14cc08a25aaa56c941f038c0e3d8e340129492c3e2824401bdd66","src/chacha.rs":"1ce534f0a3c6d3cd86aa077a56feb72969cbe4d37237ef6c698623a768a48f7f","src/guts.rs":"e8ff037f9461cdbdd8338927acfdef1497b11fa695fdd4247ec7f081bb5f459f","src/lib.rs":"a27fe2bff676a764d43d604a20cf30a41dc1c5ef4053eb41129d2479f5ae83fe"},"package":"f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"}
|
|
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.2.2] - 2020-03-09
|
||||
- Integrate `c2-chacha`, reducing dependency count (#931)
|
||||
- Add CryptoRng to ChaChaXCore (#944)
|
||||
|
||||
## [0.2.1] - 2019-07-22
|
||||
- Force enable the `simd` feature of `c2-chacha` (#845)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
[package]
|
||||
edition = "2018"
|
||||
name = "rand_chacha"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
authors = ["The Rand Project Developers", "The Rust Project Developers", "The CryptoCorrosion Contributors"]
|
||||
description = "ChaCha random number generator\n"
|
||||
homepage = "https://crates.io/crates/rand_chacha"
|
||||
|
@ -21,10 +21,10 @@ documentation = "https://rust-random.github.io/rand/rand_chacha/"
|
|||
readme = "README.md"
|
||||
keywords = ["random", "rng", "chacha"]
|
||||
categories = ["algorithms", "no-std"]
|
||||
license = "MIT/Apache-2.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-random/rand"
|
||||
[dependencies.c2-chacha]
|
||||
version = "0.2.2"
|
||||
[dependencies.ppv-lite86]
|
||||
version = "0.2.6"
|
||||
features = ["simd"]
|
||||
default-features = false
|
||||
|
||||
|
@ -34,7 +34,7 @@ version = "0.5"
|
|||
[features]
|
||||
default = ["std", "simd"]
|
||||
simd = []
|
||||
std = ["c2-chacha/std"]
|
||||
std = ["ppv-lite86/std"]
|
||||
[badges.appveyor]
|
||||
repository = "rust-random/rand"
|
||||
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
|
||||
//! The ChaCha random number generator.
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std as core;
|
||||
#[cfg(not(feature = "std"))]
|
||||
use core;
|
||||
#[cfg(not(feature = "std"))] use core;
|
||||
#[cfg(feature = "std")] use std as core;
|
||||
|
||||
use c2_chacha::guts::ChaCha;
|
||||
use self::core::fmt;
|
||||
use crate::guts::ChaCha;
|
||||
use rand_core::block::{BlockRng, BlockRngCore};
|
||||
use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
|
||||
|
||||
|
@ -22,16 +20,21 @@ const STREAM_PARAM_NONCE: u32 = 1;
|
|||
const STREAM_PARAM_BLOCK: u32 = 0;
|
||||
|
||||
pub struct Array64<T>([T; 64]);
|
||||
impl<T> Default for Array64<T> where T: Default {
|
||||
impl<T> Default for Array64<T>
|
||||
where T: Default
|
||||
{
|
||||
#[rustfmt::skip]
|
||||
fn default() -> Self {
|
||||
Self([T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default()])
|
||||
Self([
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(), T::default(),
|
||||
])
|
||||
}
|
||||
}
|
||||
impl<T> AsRef<[T]> for Array64<T> {
|
||||
|
@ -44,7 +47,9 @@ impl<T> AsMut<[T]> for Array64<T> {
|
|||
&mut self.0
|
||||
}
|
||||
}
|
||||
impl<T> Clone for Array64<T> where T: Copy + Default {
|
||||
impl<T> Clone for Array64<T>
|
||||
where T: Copy + Default
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
let mut new = Self::default();
|
||||
new.0.copy_from_slice(&self.0);
|
||||
|
@ -79,7 +84,7 @@ macro_rules! chacha_impl {
|
|||
fn generate(&mut self, r: &mut Self::Results) {
|
||||
// Fill slice of words by writing to equivalent slice of bytes, then fixing endianness.
|
||||
self.state.refill4($rounds, unsafe {
|
||||
core::mem::transmute::<&mut Array64<u32>, &mut [u8; 256]>(&mut *r)
|
||||
&mut *(&mut *r as *mut Array64<u32> as *mut [u8; 256])
|
||||
});
|
||||
for x in r.as_mut() {
|
||||
*x = x.to_le();
|
||||
|
@ -95,6 +100,8 @@ macro_rules! chacha_impl {
|
|||
}
|
||||
}
|
||||
|
||||
impl CryptoRng for $ChaChaXCore {}
|
||||
|
||||
/// A cryptographically secure random number generator that uses the ChaCha algorithm.
|
||||
///
|
||||
/// ChaCha is a stream cipher designed by Daniel J. Bernstein[^1], that we use as an RNG. It is
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
#[cfg(feature = "rustcrypto_api")]
|
||||
pub use stream_cipher::generic_array;
|
||||
// Copyright 2019 The CryptoCorrosion Contributors
|
||||
// Copyright 2020 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 ChaCha random number generator.
|
||||
|
||||
use ppv_lite86::{dispatch, dispatch_light128};
|
||||
|
||||
pub use ppv_lite86::Machine;
|
||||
use ppv_lite86::{vec128_storage, ArithOps, BitOps32, LaneWords4, MultiLane, StoreBytes, Vec4};
|
||||
|
@ -66,60 +76,12 @@ impl ChaCha {
|
|||
((d.extract(1) as u64) << 32) | d.extract(0) as u64
|
||||
}
|
||||
|
||||
/// Set 64-bit block count, affecting next refill.
|
||||
#[inline(always)]
|
||||
pub(crate) fn seek64<M: Machine>(&mut self, m: M, blockct: u64) {
|
||||
let d: M::u32x4 = m.unpack(self.d);
|
||||
self.d = d
|
||||
.insert((blockct >> 32) as u32, 1)
|
||||
.insert(blockct as u32, 0)
|
||||
.into();
|
||||
}
|
||||
|
||||
/// Set 32-bit block count, affecting next refill.
|
||||
#[inline(always)]
|
||||
pub(crate) fn seek32<M: Machine>(&mut self, m: M, blockct: u32) {
|
||||
let d: M::u32x4 = m.unpack(self.d);
|
||||
self.d = d.insert(blockct, 0).into();
|
||||
}
|
||||
|
||||
/// Produce output from the current state.
|
||||
#[inline(always)]
|
||||
fn output_narrow<M: Machine>(&mut self, m: M, x: State<M::u32x4>, out: &mut [u8; BLOCK]) {
|
||||
let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
|
||||
(x.a + k).write_le(&mut out[0..16]);
|
||||
(x.b + m.unpack(self.b)).write_le(&mut out[16..32]);
|
||||
(x.c + m.unpack(self.c)).write_le(&mut out[32..48]);
|
||||
(x.d + m.unpack(self.d)).write_le(&mut out[48..64]);
|
||||
}
|
||||
|
||||
/// Add one to the block counter (no overflow check).
|
||||
#[inline(always)]
|
||||
fn inc_block_ct<M: Machine>(&mut self, m: M) {
|
||||
let mut pos = self.pos64(m);
|
||||
let d0: M::u32x4 = m.unpack(self.d);
|
||||
pos += 1;
|
||||
let d1 = d0.insert((pos >> 32) as u32, 1).insert(pos as u32, 0);
|
||||
self.d = d1.into();
|
||||
}
|
||||
|
||||
/// Produce 4 blocks of output, advancing the state
|
||||
#[inline(always)]
|
||||
pub fn refill4(&mut self, drounds: u32, out: &mut [u8; BUFSZ]) {
|
||||
refill_wide(self, drounds, out)
|
||||
}
|
||||
|
||||
/// Produce a block of output, advancing the state
|
||||
#[inline(always)]
|
||||
pub fn refill(&mut self, drounds: u32, out: &mut [u8; BLOCK]) {
|
||||
refill_narrow(self, drounds, out)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn refill_rounds(&mut self, drounds: u32) -> State<vec128_storage> {
|
||||
refill_narrow_rounds(self, drounds)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_stream_param(&mut self, param: u32, value: u64) {
|
||||
set_stream_param(self, param, value)
|
||||
|
@ -133,10 +95,7 @@ impl ChaCha {
|
|||
|
||||
#[inline(always)]
|
||||
fn refill_wide_impl<Mach: Machine>(
|
||||
m: Mach,
|
||||
state: &mut ChaCha,
|
||||
drounds: u32,
|
||||
out: &mut [u8; BUFSZ],
|
||||
m: Mach, state: &mut ChaCha, drounds: u32, out: &mut [u8; BUFSZ],
|
||||
) {
|
||||
let k = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
|
||||
let mut pos = state.pos64(m);
|
||||
|
@ -196,23 +155,8 @@ dispatch!(m, Mach, {
|
|||
}
|
||||
});
|
||||
|
||||
/// Refill the buffer from a single-block round, updating the block count.
|
||||
dispatch_light128!(m, Mach, {
|
||||
fn refill_narrow(state: &mut ChaCha, drounds: u32, out: &mut [u8; BLOCK]) {
|
||||
let x = refill_narrow_rounds(state, drounds);
|
||||
let x = State {
|
||||
a: m.unpack(x.a),
|
||||
b: m.unpack(x.b),
|
||||
c: m.unpack(x.c),
|
||||
d: m.unpack(x.d),
|
||||
};
|
||||
state.output_narrow(m, x, out);
|
||||
state.inc_block_ct(m);
|
||||
}
|
||||
});
|
||||
|
||||
/// Single-block, rounds-only; shared by try_apply_keystream for tails shorter than BUFSZ
|
||||
/// and XChaCha's setup step.
|
||||
// Single-block, rounds-only; shared by try_apply_keystream for tails shorter than BUFSZ
|
||||
// and XChaCha's setup step.
|
||||
dispatch!(m, Mach, {
|
||||
fn refill_narrow_rounds(state: &mut ChaCha, drounds: u32) -> State<vec128_storage> {
|
||||
let k: Mach::u32x4 = m.vec([0x6170_7865, 0x3320_646e, 0x7962_2d32, 0x6b20_6574]);
|
|
@ -8,21 +8,24 @@
|
|||
|
||||
//! The ChaCha random number generator.
|
||||
|
||||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
|
||||
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://rust-random.github.io/rand/")]
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
|
||||
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://rust-random.github.io/rand/"
|
||||
)]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![doc(test(attr(allow(unused_variables), deny(warnings))))]
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
pub use rand_core;
|
||||
|
||||
mod chacha;
|
||||
mod guts;
|
||||
|
||||
pub use crate::chacha::{ChaCha12Core, ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Core, ChaCha8Rng};
|
||||
pub use crate::chacha::{
|
||||
ChaCha12Core, ChaCha12Rng, ChaCha20Core, ChaCha20Rng, ChaCha8Core, ChaCha8Rng,
|
||||
};
|
||||
|
||||
/// ChaCha with 20 rounds
|
||||
pub type ChaChaRng = ChaCha20Rng;
|
||||
|
|
Загрузка…
Ссылка в новой задаче