整数乱数の生成
Rust の標準ライブラリには乱数生成モジュールは含まれないため、外部の rand crate を利用する必要があります。
動作環境
- Windows 11
- WSL Ubuntu 20.04
- Rust 1.64.0
サンプルプロジェクトの作成
今回利用するサンプルプロジェクトを作成します。
$ cargo new rand-sample
依存パッケージに rand を追加します。
[package]
name = "rand-sample"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8.5"
整数乱数の生成 その1
乱数を生成するための最も単純な方法は rand::random
を呼び出すことです。
fn main() {
println!("{}", rand::random::<i32>());
println!("{}", rand::random::<i32>());
println!("{}", rand::random::<i32>());
}
$ cargo run
1014175463
-1118522608
-233617653
整数乱数の生成 その2
より実用的には、rand::thread_rng()
を呼び出します。
rng はおそらく、Random Number Generator の略です。
その1で利用した rand::random
は、rand::thread_rng().gen()
を簡易的に実行するものであり、乱数シードによる初期化のオーバーヘッドが毎回発生してしまいます。
rand::thread_rng()
を利用することで、初期化と乱数生成を分離して実行することができます。
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
println!("{}", rng.gen::<i32>());
println!("{}", rng.gen::<i32>());
println!("{}", rng.gen::<i32>());
}
$ cargo run
1824664652
909867432
-767794661
実行時間比較
rand::random
と rand::thread_rng
の実行時間を比較してみます。
それぞれの手法に対して、1億回乱数を生成させた時間を計測します。
rand::random
実行時間
fn main() {
let mut v = Vec::<i32>::new();
for _ in 0..100_000_000 {
v.push(rand::random());
}
}
$ time cargo run
real 0m36.066s
user 0m35.975s
sys 0m0.090s
rand::random
では 36 秒の時間を要しました。
rand::thread_rng
実行時間
use rand::Rng;
fn main() {
let mut v = Vec::<i32>::new();
let mut rng = rand::thread_rng();
for _ in 0..100_000_000 {
v.push(rng.gen());
}
}
$ time cargo run
real 0m28.514s
user 0m28.413s
sys 0m0.100s
rng を生成して rng.gen
を実行する手法では、28.5 秒の時間を要しました。thread_rng
の方が実行効率が良いことがわかります。
範囲指定の乱数生成
Rng
に対して gen_range
メソッドを呼び出すことで、乱数の範囲を指定することもできます。
次の例では、0 以上 10 未満の整数を3回生成しています。
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
println!("{}", rng.gen_range(0..10));
println!("{}", rng.gen_range(0..10));
println!("{}", rng.gen_range(0..10));
}
$ cargo run
7
1
4
【関連記事】
rand crate を利用することで、整数型以外の乱数も生成可能です。
例として、以下の記事では浮動小数点数の乱数を生成しています。