commit fc832a1340028aeadc1ee5f37debba44309d228e Author: Pascal Engélibert Date: Sun Jan 18 10:41:59 2026 +0100 Initial commit diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..ddff440 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-C", "target-cpu=native"] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..feb3e39 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "rust-analyzer.server.extraEnv": { + "RUSTFLAGS": "-Ctarget-feature=+avx2" + }, +} diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..f103fbf --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,454 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "acorn_prng" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f224b4cf75de46f7bef9aaf23dde63dfa1c78ab1d05ffe189bef411a2d4552d6" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-prng" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57f046e8d101730fbdeae5326e5487da8239c0fdf3ce00ea949e912ea5b02057" +dependencies = [ + "aes", + "byteorder", + "rand", +] + +[[package]] +name = "bsd4random" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2f52a0d83e309518ba7c6abc628e21b6009780d5303b1367e6779db50e96d2" + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "fast_rands" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8ebb9ce3ecacec6752be7cbd8bbf98931ae760a78c7030712be9503b8ed12a" +dependencies = [ + "rustversion", + "serde", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "frand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0632aefca5b3940174bbea720a111b3ec3433a67852ab737299565c3ce2d32b4" +dependencies = [ + "glam", + "rand_core 0.6.4", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "mcg59" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f5ee5f652ce574e8affb2b8d63af81c0a4de437d70f727ea6c079bca9398b86" + +[[package]] +name = "nanorand" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3d189da485332e96ba8a5ef646a311871abd7915bf06ac848a9117f19cf6e4" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prng_mt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c102f2e5b3db881172fe001d9956cd07aa9f8a37ed366497032e61abed01c937" + +[[package]] +name = "proc-macro2" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quad-rand" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a651516ddc9168ebd67b24afd085a718be02f8858fe406591b013d101ce2f40" + +[[package]] +name = "quote" +version = "1.0.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xoshiro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "randbench" +version = "0.1.0" +dependencies = [ + "acorn_prng", + "aes-prng", + "bsd4random", + "fast_rands", + "fastrand", + "frand", + "mcg59", + "nanorand", + "prng_mt", + "quad-rand", + "rand", + "rand_core 0.6.4", + "rand_xoshiro", + "romu", + "shishua", + "simd_rand", + "simplerand", + "tiny_prng", + "tinyrand", + "wyhash", + "wyrand", +] + +[[package]] +name = "romu" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd731b0b5899480a0d7cf3b9ce744a92793c98c092f9d6f0a8133ef9fe8024b1" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shishua" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038fba6c335358daf04da1b52818fdbb71688e228889d11eec4c748a04b8bd59" +dependencies = [ + "bytemuck", + "byteorder", + "rand_core 0.9.5", +] + +[[package]] +name = "simd_rand" +version = "0.1.0" +source = "git+https://github.com/martinothamar/simd-rand.git?rev=faff5f147e2e9d57385f94a7c3f2f72ae212ab16#faff5f147e2e9d57385f94a7c3f2f72ae212ab16" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "simplerand" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e111daec97c913e764c730b11de670f36adfc9ef87c791ee8999ecc3ded8f644" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tiny_prng" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85376baaf83e59c30280147f0e7c34c03df4515645d73624701ccdb610359969" + +[[package]] +name = "tinyrand" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ffaad2263779579369d45f65cad0647c860893d27e4543cdcc1e428d07da2c" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "wyhash" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca4d373340c479fd1e779f7a763acee85da3e423b1a9a9acccf97babcc92edbb" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "wyrand" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e0359b0b8d9cdef235a1fd4a8c5d02e4c9204e9fac861c14c229a8e803d1a6" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "zerocopy" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a53fd50 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "randbench" +version = "0.1.0" +edition = "2024" + +[dependencies] +aes-prng = "0.2.2" +acorn_prng = "4.0.0" +bsd4random = "0.9.0" +fast_rands = { version = "0.15.4", default-features = false, features = ["std"] } +fastrand = "2.3.0" +frand = "0.10.1" +mcg59 = "0.9.4" +nanorand = "0.8.0" +prng_mt = "0.1.0" +quad-rand = "0.2.3" +rand = "0.9.2" +rand_core_06 = { package = "rand_core", version = "0.6.4" } +rand_xoshiro = "0.7.0" +romu = "0.7.0" +shishua = "0.2.0" +simd_rand = { git = "https://github.com/martinothamar/simd-rand.git", rev = "faff5f147e2e9d57385f94a7c3f2f72ae212ab16" } +simplerand = "1.6.0" +tiny_prng = "0.2.5" +tinyrand = "0.5.0" +wyhash = "0.6.0" +wyrand = "0.3.2" + +[profile.release] +lto = "fat" diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc5bfbd --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +# Benchmark of Rust PRNG crates + +Simple performance benchmark of pseudorandom generation Rust crates for **non-cryptographic** purposes such as games. + +The goal is not to compare algorithms, but implementations that can be used immediately by a Rust developer. + +Inclusion criteria: +* Seedable. Needed for reproducibility. +* Simple to use, either thanks to an obvious API or examples in documentation. +* Works on common targets. +* Usable for generating bytes or groups of bytes. +* Builds on my system. + +**Warning**: If your need has anything to do with security, i.e. generating values seeded by or interacting with potentially untrusted data or that should be secret or not leak information about the seed or correlation between multiple outputs, then you should instead use a CSPRNG. + +## Results + +```bash +RUSTFLAGS='-C target-cpu=native' cargo run --release +``` + +Results on AMD Ryzen 7 5700X: (with AVX2) + +``` +Time (s) PRNG +0.06681618 frand::Rand +0.06935108 simd_rand::portable::xoshiro256plusplusx4::Xoshiro256PlusPlusX4 +0.07013825 simd_rand::specific::avx2::xoshiro256plus::Xoshiro256PlusX4 +0.070464075 simd_rand::specific::avx2::xoshiro256plusplus::Xoshiro256PlusPlusX4 +0.07331398 simd_rand::portable::xoshiro256plusx8::Xoshiro256PlusX8 +0.07332602 simd_rand::portable::xoshiro256plusplusx8::Xoshiro256PlusPlusX8 +0.07440938 simd_rand::portable::xoshiro256plusx4::Xoshiro256PlusX4 +0.077901766 fast_rands::RomuDuoJrRand +0.07997875 rand_xoshiro::xoshiro256plus::Xoshiro256Plus +0.08022531 wyhash::v1::traits::WyRng +0.08147533 romu::Rng +0.082410775 fast_rands::RomuTrioRand +0.08576214 rand_xoshiro::xoshiro256starstar::Xoshiro256StarStar +0.08702609 wyhash::final3::traits::WyRng +0.087389685 wyrand::final_v4_2::wyrand::WyRand +0.08785791 tinyrand::wyrand::Wyrand +0.08805069 fastrand::Rng +0.088699095 simd_rand::specific::avx2::shishua::Shishua<32768> +0.089351326 rand_xoshiro::xoroshiro128plus::Xoroshiro128Plus +0.090053834 fast_rands::Xoshiro256PlusPlusRand +0.09293575 rand::rngs::small::SmallRng +0.09571917 rand_xoshiro::xoshiro256plusplus::Xoshiro256PlusPlus +0.09630984 rand_xoshiro::xoshiro512plus::Xoshiro512Plus +0.09719508 tiny_prng::pcg::PcgXslRr6432Mcg +0.10209641 rand_xoshiro::xoshiro512starstar::Xoshiro512StarStar +0.10582184 rand_xoshiro::xoroshiro128starstar::Xoroshiro128StarStar +0.107617944 rand_xoshiro::xoshiro512plusplus::Xoshiro512PlusPlus +0.11635949 tinyrand::xorshift::Xorshift +0.11716504 rand_xoshiro::xoroshiro128plusplus::Xoroshiro128PlusPlus +0.12221907 shishua::core::ShiShuAState +0.1273574 tiny_prng::pcg::PcgXslRrMcg +0.13119678 tiny_prng::xorshift::Xorshift1024star +0.13813396 tiny_prng::xorshift::Xorshift128 +0.14830554 rand_xoshiro::splitmix64::SplitMix64 +0.1490197 fast_rands::Sfc64Rand +0.15220404 tiny_prng::pcg::PcgXslRr +0.15493397 tinyrand::splitmix::SplitMix +0.16185075 rand_xoshiro::xoshiro128plus::Xoshiro128Plus +0.17024948 bsd4random::BSD +0.17189687 prng_mt::mt19937::MT19937_64 +0.1737906 fast_rands::XorShift64Rand +0.17380002 tiny_prng::xorshift::Xorshift64 +0.17656836 fast_rands::Lehmer64Rand +0.18433817 mcg59::MCG59 +0.18995807 tiny_prng::xorshift::Xorshift64star +0.19150706 rand_xoshiro::xoshiro128plusplus::Xoshiro128PlusPlus +0.19262685 rand_xoshiro::xoshiro128starstar::Xoshiro128StarStar +0.20068832 tiny_prng::mt64::Mt19937 +0.2185049 aes_prng::AesRng +0.23102058 rand_xoshiro::xoroshiro64star::Xoroshiro64Star +0.23144223 tiny_prng::pcg::PcgXshRs6432 +0.23157886 tiny_prng::pcg::PcgXshRr6432 +0.25709888 rand_xoshiro::xoroshiro64starstar::Xoroshiro64StarStar +0.28615955 rand::rngs::std::StdRng +0.29523018 prng_mt::mt19937::MT19937 +0.31545836 quad_rand::RandGenerator +0.34703827 tiny_prng::xorshift::Xorshift32 +0.34762907 nanorand::rand::wyrand::WyRand +0.39694864 tiny_prng::mt::Mt19937 +0.46873802 nanorand::rand::pcg64::Pcg64 +0.8413978 nanorand::rand::chacha::ChaCha<8> +1.769573 shishua::rand::ShiShuARng +3.5496118 acorn_prng::Acorn +3.7084286 simplerand::Random +``` + +[FRand](https://crates.io/crates/frand) is the fastest, however it has no particular mathematical justification beyond the fact its parameters were found empirically to minimize bias. + +[simd_rand](https://github.com/martinothamar/simd-rand) provides the fastest implementations of common PRNGs. The best on my computer (without AVX512) was a portable one, probably thanks to compiler autovectorization. Sadly this crate is not published on crates.io, only on GitHub. + +[fast_rands](https://crates.io/crates/fast_rands) implements RomuDuoJr, the fastest after `simd_rand`. It is part of the Romu family which [has been studied](https://arxiv.org/pdf/2002.11331). It provides good quality up to at least 2^48 bytes. However this crate has too many dependencies that should not be necessary if you only want a PRNG, so copying the wanted functions can be an option. + +Surprisingly, the AES PRNG is quite fast, probably due to the AES instruction set. + +Also to my surprise, Shishua was slower than RomuTrio, contrarily to [the author's claim](https://espadrine.github.io/blog/posts/shishua-the-fastest-prng-in-the-world.html). Maybe that's the implementation's fault or my lack of AVX512, I should investigate. The streaming overhead can be significant, as we see with `ShiShuARng` which is very slow compared to the bare `ShiShuAState`. `simd_rand`'s implementation is quite faster. diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..843c6fe --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,9 @@ +hard_tabs = true +newline_style = "unix" +imports_granularity = "Crate" + +unstable_features = true +format_code_in_doc_comments = true +format_macro_bodies = true +format_macro_matchers = true +format_strings = true diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..752e2d5 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,1083 @@ +#![feature(portable_simd)] + +use std::{fmt::Debug, hint::black_box, ops::BitXor}; + +fn main() { + let seed_u32 = 0xabcd_ef01; + let seed_u64 = 0xabcd_ef01_2345_6789; + let seed_i64 = 0x0123_4567_89ab_cdef; + let seed_u128 = 0xabcd_ef01_2345_6789_abcd_ef01_2345_6789; + let seed_u64_4 = [ + 0xabcd_ef01_2345_6789, + 0xef01_abcd_6789_2345, + 0x5432_dcba_6789_10fe, + 0x1122_3344_5566_7788, + ]; + let seed_u64_16 = [ + 0xabcd_ef01_2345_6789, + 0xef01_abcd_6789_2345, + 0x5432_dcba_6789_10fe, + 0x1122_3344_5566_7788, + 0xabcd_ef01_2345_6789, + 0xef01_abcd_6789_2345, + 0x5432_dcba_6789_10fe, + 0x1122_3344_5566_7788, + 0xabcd_ef01_2345_6789, + 0xef01_abcd_6789_2345, + 0x5432_dcba_6789_10fe, + 0x1122_3344_5566_7788, + 0xabcd_ef01_2345_6789, + 0xef01_abcd_6789_2345, + 0x5432_dcba_6789_10fe, + 0x1122_3344_5566_7788, + ]; + let seed_u8_8 = [1, 2, 3, 4, 5, 6, 7, 8]; + let seed_u8_16 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + let seed_u8_32 = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, + ]; + let seed_u8_64 = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + ]; + + // We could transmute instead, but here we prefer to avoid the risk of frightening the compiler! + let mut output_u8 = vec![0; 1024 * 1024 * 1024]; + let mut output_u64 = vec![0; 1024 * 1024 * 1024 / 8]; + let mut output_i64 = vec![0; 1024 * 1024 * 1024 / 8]; + let mut output_i32 = vec![0; 1024 * 1024 * 1024 / 4]; + let mut output_u32 = vec![0; 1024 * 1024 * 1024 / 4]; + let mut output_u128 = vec![0; 1024 * 1024 * 1024 / 16]; + + let mut bench = Bench::default(); + + bench.run_bench::(seed_u8_8, &mut output_u8); + bench.run_bench::(seed_u8_16, &mut output_u8); + bench.run_bench::(seed_u8_16, &mut output_u8); + bench.run_bench::(seed_u8_16, &mut output_u8); + bench.run_bench::(seed_u8_8, &mut output_u8); + bench.run_bench::(seed_u8_8, &mut output_u8); + bench.run_bench::(seed_u8_16, &mut output_u8); + bench.run_bench::(seed_u8_16, &mut output_u8); + bench.run_bench::(seed_u8_16, &mut output_u8); + bench.run_bench::(seed_u8_32, &mut output_u8); + bench.run_bench::(seed_u8_32, &mut output_u8); + bench.run_bench::(seed_u8_32, &mut output_u8); + bench.run_bench::(seed_u8_64, &mut output_u8); + bench.run_bench::(seed_u8_64, &mut output_u8); + bench.run_bench::(seed_u8_64, &mut output_u8); + bench.run_bench::(seed_u64, &mut output_u8); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u8); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u32, &mut output_i32); + bench.run_bench::(seed_i64, &mut output_i64); + bench.run_bench::((seed_u8_32, [0; 8], seed_u8_8), &mut output_u8); + bench.run_bench::(seed_u128, &mut output_u8); + bench.run_bench::(seed_u64, &mut output_u8); + bench.run_bench::(seed_u64, &mut output_u32); + bench.run_bench::(seed_u64, &mut output_u8); + bench.run_bench::(seed_u64_4, &mut output_u64); + bench.run_bench::(seed_u128, &mut output_u8); + bench.run_bench::(seed_u8_32, &mut output_u8); + bench.run_bench::(seed_u8_32, &mut output_u8); + bench.run_bench::(seed_u8_16, &mut output_u8); + bench.run_bench::(seed_u128, &mut output_u64); + bench.run_bench::(seed_u32, &mut output_u32); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64_4, &mut output_u32); + bench.run_bench::(seed_u64_4, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u32); + bench.run_bench::(seed_u64, &mut output_u32); + bench.run_bench::(seed_u128, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u32); + bench.run_bench::(seed_u128, &mut output_u64); + bench.run_bench::(seed_u64_16, &mut output_u64); + bench.run_bench::(seed_u128, &mut output_u128); + bench.run_bench::(seed_u32, &mut output_u32); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u8_8, &mut output_u8); + bench.run_bench::(seed_u8_8, &mut output_u8); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + #[cfg(all(target_arch = "x86_64", target_feature = "avx2"))] + { + bench.run_bench::>(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + bench.run_bench::(seed_u64, &mut output_u64); + } + + bench.results.sort_by(|(_name1, time1), (_name2, time2)| time1.partial_cmp(time2).unwrap()); + + println!(); + println!("Time (s)\tPRNG"); + for (name, time) in bench.results { + println!("{time}\t{name}"); + } +} + +#[derive(Default)] +struct Bench { + results: Vec<(String, f32)>, +} + +impl Bench { + fn run_bench(&mut self, seed: R::Seed, output: &mut [R::Output]) + where + R::Output: BitXor + Copy + Debug + Default, + { + let mut rng = ::new(seed); + let now = std::time::Instant::now(); + black_box(rng.generate(black_box(output))); + let time = now.elapsed(); + + // Ensure the compiler does not optimize out the writes + let sum = output.iter().fold(R::Output::default(), |sum, i| sum ^ *i); + + let secs = time.as_secs_f32(); + let name = std::any::type_name::(); + println!("{}\t{}\t{:?}", secs, name, sum); + self.results.push((name.to_string(), secs)); + } +} + +trait RandProvider { + type Seed; + type Output; + fn new(seed: Self::Seed) -> Self; + fn generate(&mut self, output: &mut [Self::Output]); +} + +impl RandProvider for rand_xoshiro::SplitMix64 { + type Seed = [u8; 8]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoroshiro128Plus { + type Seed = [u8; 16]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoroshiro128PlusPlus { + type Seed = [u8; 16]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoroshiro128StarStar { + type Seed = [u8; 16]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoroshiro64Star { + type Seed = [u8; 8]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoroshiro64StarStar { + type Seed = [u8; 8]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro128Plus { + type Seed = [u8; 16]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro128PlusPlus { + type Seed = [u8; 16]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro128StarStar { + type Seed = [u8; 16]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro256Plus { + type Seed = [u8; 32]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro256PlusPlus { + type Seed = [u8; 32]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro256StarStar { + type Seed = [u8; 32]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro512Plus { + type Seed = [u8; 64]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(rand_xoshiro::Seed512(seed)) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro512PlusPlus { + type Seed = [u8; 64]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(rand_xoshiro::Seed512(seed)) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand_xoshiro::Xoshiro512StarStar { + type Seed = [u8; 64]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(rand_xoshiro::Seed512(seed)) + } + + fn generate(&mut self, output: &mut [u8]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for fastrand::Rng { + type Seed = u64; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [u8]) { + self.fill(output); + } +} + +impl RandProvider for fast_rands::Lehmer64Rand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use fast_rands::Rand; + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for fast_rands::RomuDuoJrRand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use fast_rands::Rand; + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for fast_rands::RomuTrioRand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use fast_rands::Rand; + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for fast_rands::XorShift64Rand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use fast_rands::Rand; + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for fast_rands::Xoshiro256PlusPlusRand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use fast_rands::Rand; + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for fast_rands::Sfc64Rand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use fast_rands::Rand; + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for romu::Rng { + type Seed = u64; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + Self::from_seed_with_64bit(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + self.fill_bytes(output); + } +} + +impl RandProvider for tinyrand::SplitMix { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use tinyrand::Seeded; + Self::seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use tinyrand::Rand; + for i in output.iter_mut() { + *i = self.next_u64(); + } + } +} + +impl RandProvider for tinyrand::Wyrand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use tinyrand::Seeded; + Self::seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use tinyrand::Rand; + for i in output.iter_mut() { + *i = self.next_u64(); + } + } +} + +impl RandProvider for tinyrand::Xorshift { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use tinyrand::Seeded; + Self::seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use tinyrand::Rand; + for i in output.iter_mut() { + *i = self.next_u64(); + } + } +} + +impl RandProvider for bsd4random::BSD { + type Seed = u32; + type Output = i32; + fn new(seed: Self::Seed) -> Self { + Self::srand(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.rand(); + } + } +} + +impl RandProvider for mcg59::MCG59 { + type Seed = i64; + type Output = i64; + fn new(seed: Self::Seed) -> Self { + Self::seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for nanorand::ChaCha8 { + type Seed = ([u8; 32], [u8; 8], [u8; 8]); + type Output = u8; + fn new(seed: Self::Seed) -> Self { + Self::new_key(seed.0, seed.1, seed.2) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use nanorand::Rng; + self.fill_bytes(output); + } +} + +impl RandProvider for nanorand::Pcg64 { + type Seed = u128; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + Self::new_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use nanorand::Rng; + self.fill_bytes(output); + } +} + +impl RandProvider for nanorand::WyRand { + type Seed = u64; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + Self::new_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use nanorand::Rng; + self.fill_bytes(output); + } +} + +impl RandProvider for quad_rand::RandGenerator { + type Seed = u64; + type Output = u32; + fn new(seed: Self::Seed) -> Self { + let rng = Self::new(); + rng.srand(seed); + rng + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.rand(); + } + } +} + +impl RandProvider for shishua::ShiShuARng { + type Seed = u64; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::seed_from_u64(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for shishua::ShiShuAState { + type Seed = [u64; 4]; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::new(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.chunks_exact_mut(16) { + *(<&mut [u64; 16]>::try_from(i).unwrap()) = self.round_unpack(); + } + } +} + +impl RandProvider for simplerand::Random { + type Seed = u128; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + Self::new(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.rand() + } + } +} + +impl RandProvider for rand::prelude::StdRng { + type Seed = [u8; 32]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for rand::prelude::SmallRng { + type Seed = [u8; 32]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for aes_prng::AesRng { + type Seed = [u8; 16]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for acorn_prng::Acorn { + type Seed = u128; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::new(acorn_prng::Order::new(45), acorn_prng::Seed::new(seed)) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate_u64_between_range(0..=u64::MAX) + } + } +} + +impl RandProvider for prng_mt::MT19937 { + type Seed = u32; + type Output = u32; + fn new(seed: Self::Seed) -> Self { + Self::new(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for prng_mt::MT19937_64 { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::new(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.next(); + } + } +} + +impl RandProvider for tiny_prng::mt::Mt19937 { + type Seed = [u64; 4]; + type Output = u32; + fn new(seed: Self::Seed) -> Self { + Self::with_array(seed.to_vec()) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::mt64::Mt19937 { + type Seed = [u64; 4]; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_array(seed.to_vec()) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::pcg::PcgXshRr6432 { + type Seed = u64; + type Output = u32; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::pcg::PcgXshRs6432 { + type Seed = u64; + type Output = u32; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::pcg::PcgXslRr { + type Seed = u128; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::pcg::PcgXslRr6432Mcg { + type Seed = u64; + type Output = u32; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::pcg::PcgXslRrMcg { + type Seed = u128; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::xorshift::Xorshift1024star { + type Seed = [u64; 16]; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::xorshift::Xorshift128 { + type Seed = u128; + type Output = u128; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::xorshift::Xorshift32 { + type Seed = u32; + type Output = u32; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::xorshift::Xorshift64 { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for tiny_prng::xorshift::Xorshift64star { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.generate(); + } + } +} + +impl RandProvider for wyrand::WyRand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::new(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.rand(); + } + } +} + +impl RandProvider for wyhash::WyRng { + type Seed = [u8; 8]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for wyhash::final3::WyRng { + type Seed = [u8; 8]; + type Output = u8; + fn new(seed: Self::Seed) -> Self { + use rand::{SeedableRng}; + Self::from_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use rand::RngCore; + self.fill_bytes(output); + } +} + +impl RandProvider for frand::Rand { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + Self::with_seed(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + for i in output.iter_mut() { + *i = self.r#gen(); + } + } +} + +impl RandProvider for simd_rand::portable::Xoshiro256PlusPlusX4 { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use rand_core_06::{SeedableRng}; + Self::seed_from_u64(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use simd_rand::portable::SimdRandX4; + for i in output.chunks_exact_mut(4) { + *(<&mut [u64; 4]>::try_from(i).unwrap()) = self.next_u64x4().to_array(); + } + } +} + +impl RandProvider for simd_rand::portable::Xoshiro256PlusPlusX8 { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use rand_core_06::{SeedableRng}; + Self::seed_from_u64(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use simd_rand::portable::SimdRandX8; + for i in output.chunks_exact_mut(8) { + *(<&mut [u64; 8]>::try_from(i).unwrap()) = self.next_u64x8().to_array(); + } + } +} + +impl RandProvider for simd_rand::portable::Xoshiro256PlusX4 { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use rand_core_06::{SeedableRng}; + Self::seed_from_u64(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use simd_rand::portable::SimdRandX4; + for i in output.chunks_exact_mut(4) { + *(<&mut [u64; 4]>::try_from(i).unwrap()) = self.next_u64x4().to_array(); + } + } +} + +impl RandProvider for simd_rand::portable::Xoshiro256PlusX8 { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use rand_core_06::{SeedableRng}; + Self::seed_from_u64(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use simd_rand::portable::SimdRandX8; + for i in output.chunks_exact_mut(8) { + *(<&mut [u64; 8]>::try_from(i).unwrap()) = self.next_u64x8().to_array(); + } + } +} + +#[cfg(all(target_arch = "x86_64", target_feature = "avx2"))] +impl RandProvider for simd_rand::specific::avx2::Shishua<{simd_rand::specific::avx2::DEFAULT_BUFFER_SIZE}> { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use rand_core_06::{SeedableRng}; + Self::seed_from_u64(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use simd_rand::specific::avx2::SimdRand; + for i in output.chunks_exact_mut(4) { + *(<&mut [u64; 4]>::try_from(i).unwrap()) = *self.next_u64x4(); + } + } +} + +#[cfg(all(target_arch = "x86_64", target_feature = "avx2"))] +impl RandProvider for simd_rand::specific::avx2::Xoshiro256PlusPlusX4 { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use rand_core_06::{SeedableRng}; + Self::seed_from_u64(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use simd_rand::specific::avx2::SimdRand; + for i in output.chunks_exact_mut(4) { + *(<&mut [u64; 4]>::try_from(i).unwrap()) = *self.next_u64x4(); + } + } +} + +#[cfg(all(target_arch = "x86_64", target_feature = "avx2"))] +impl RandProvider for simd_rand::specific::avx2::Xoshiro256PlusX4 { + type Seed = u64; + type Output = u64; + fn new(seed: Self::Seed) -> Self { + use rand_core_06::{SeedableRng}; + Self::seed_from_u64(seed) + } + + fn generate(&mut self, output: &mut [Self::Output]) { + use simd_rand::specific::avx2::SimdRand; + for i in output.chunks_exact_mut(4) { + *(<&mut [u64; 4]>::try_from(i).unwrap()) = *self.next_u64x4(); + } + } +}