スポンサーリンク
Rustの乱数の使い方。
乱数を使用するためにはrandクレートを使用する。
fn main() { use rand::Rng; // 乱数を使うためにrand::Rngを使用 let mut rng = rand::thread_rng(); let min:i32 = 0; let max:i32 = 20; // 50回ループ (0..50).for_each(|_|{ let randint:i32 = rng.gen_range(min..max); // 最大・最小を指定して乱数を生成 println!("{}",randint); }); }
rand_distrクレートを使用すると分布を変えられる。rand_distr::Normalは正規分布。
[dependencies]
# 乱数を使用 https://crates.io/crates/rand
rand = "0.8.5"
# 乱数の分布を指定 https://crates.io/crates/rand_distr
rand_distr = "0.4.3"
fn main() { use rand::prelude::{Distribution, thread_rng}; use rand_distr::Normal; let mut rng = rand::thread_rng(); let mean:f32 = 10.0; let stddev:f32 = 8.0; // 平均値と標準偏差を用いた乱数生成器を作成 let normal = Normal::new( mean, // 平均 stddev // 標準偏差 ).unwrap(); // 50回ループ (0..100).for_each(|_|{ let randint:i32 = normal.sample(&mut rng) as i32; // 乱数を生成 println!("{}",randint); }); }
これだけではさすがにつまらないので、win32apiを使ってSetPixelで点を散布してみる。
以前作ったメモリデバイスコンテキストのコードで乱数のプロットを表示する。
#[path="./win32dib.rs"] mod win32dib; use win32dib::Win32DIBCanvas; use windows::{ core::*, Win32::Foundation::*, Win32::Graphics::Gdi::*, Win32::UI::WindowsAndMessaging::*, }; use once_cell::sync::Lazy; use std::sync::Mutex; // ■ Mutex ... std::sync::Mutex // ■ Lazy ... once_cell::sync::Lazy static mydib:Lazy<Mutex<Win32DIBCanvas>> = Lazy::new(|| Mutex::new( Win32DIBCanvas::new() ) ); /////////////////////////////////////////////// /// MemDCの背景をクリア ////////////////////// fn clear_mydib_background(rmdib : &mut Win32DIBCanvas){ // super::super::Foundation::COLORREF // let refmydib = &mut mydib.lock().unwrap(); let width:i32 = rmdib.bitmapInfo.bmiHeader.biWidth; let height:i32 = -rmdib.bitmapInfo.bmiHeader.biHeight; let rect:RECT = RECT{ left:0, top:0, right:width, bottom:height, }; unsafe { let whitebrush = CreateSolidBrush(COLORREF(0x00FFFFFF)); FillRect(rmdib.hMemDC,&rect,whitebrush); DeleteObject(whitebrush); } }
/////////////////////////////////////////////// /// count個の乱数を生成 fn get_random(count:i32, min:i32,max:i32) -> Vec<i32>{ use rand::Rng; // 乱数を使うためにrand::Rngを使用 let mut rng = rand::thread_rng(); let mut rlist:Vec<i32> = Vec::new(); for i in 0..count{ let randint:i32 = rng.gen_range(min..max); rlist.push(randint); } return rlist; }
/////////////////////////////////////////////// // ■ HWND ... windows::Win32::Foundation::HWND // ■ WPARAM ... windows::Win32::Foundation::WPARAM // ■ LPARAM ... windows::Win32::Foundation::LPARAM // ■ LRESULT ... windows::Win32::Foundation::LRESULT extern "system" fn wndproc(window: HWND, message: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT { unsafe { // ■ RECT ... windows::Win32::Foundation::RECT let rectnullptr: Option<*const RECT> = None; match message as u32 { WM_CREATE => { // mydib.lock().unwrap() への可変な参照をrefmydibに束縛 let refmydib = &mut mydib.lock().unwrap(); refmydib.create(640,480); clear_mydib_background(refmydib);
/////////////////////////////////////// /// 乱数で座標を作成 ////////////////// let count = 50000; let xlist:Vec<i32> = get_random(count,0,640); let ylist:Vec<i32> = get_random(count,0,480); // 点をプロット for pindex in 0..count as usize{ SetPixel( refmydib.hMemDC, xlist[pindex], ylist[pindex], COLORREF(0x00000000)); } ///////////////////////////////////////
// ■ LRESULT ... windows::Win32::Foundation::LRESULT LRESULT(0) } WM_PAINT => { // ■ PAINTSTRUCT ... windows::Win32::Graphics::Gdi::PAINTSTRUCT // ■ BeginPaint ... windows::Win32::Graphics::Gdi::BeginPaint let mut ps = PAINTSTRUCT::default(); let hdc = BeginPaint(window, &mut ps); let refmydib = &mut mydib.lock().unwrap(); ////////////////////////////////////////////////////////// // 背景をクリア /////////////////////////////////////////// let mut clientrect:RECT = RECT::default(); GetClientRect(window, &mut clientrect); let whitebrush = CreateSolidBrush(COLORREF(0x00FFFFFF)); FillRect(hdc,&clientrect,whitebrush); DeleteObject(whitebrush); ////////////////////////////////////////////////////////// // ■ BitBlt ... windows::Win32::Graphics::Gdi // ■ SRCCOPY ... windows::Win32::Graphics::Gdi::SRCCOPY BitBlt( hdc, 0, 0, 640, 480, refmydib.hMemDC, 0, 0, SRCCOPY ); // ■ EndPaint ... windows::Win32::Graphics::Gdi::EndPaint EndPaint(window, &ps); // ■ LRESULT ... windows::Win32::Foundation::LRESULT LRESULT(0) } WM_DESTROY => { println!("WM_DESTROY"); // ■ windows::Win32::UI::WindowsAndMessaging::PostQuitMessage PostQuitMessage(0); // ■ LRESULT ... windows::Win32::Foundation::LRESULT LRESULT(0) } // ■ windows::Win32::UI::WindowsAndMessaging::DefWindowProcA _ => DefWindowProcA(window, message, wparam, lparam), } } } // ■ HINSTANCE ... windows::Win32::Foundation::HINSTANCE /// 自作 WinMain pub fn WinMain( hInstance : HINSTANCE, hPrevInstance : HINSTANCE, lpCmdLine:Vec<String>, nCmdShow:i32 )->i32{ unsafe{ // ■ PCSTR ... windows::core::PCSTR // ■ windows::Win32::UI::WindowsAndMessaging::LoadCursorW // ■ windows::Win32::UI::WindowsAndMessaging::IDC_ARROW // ■ windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW // ■ windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW let _hCursor = LoadCursorW(None,IDC_ARROW).unwrap(); let _hInstance = hInstance; let _lpszClassName = PCSTR::from_raw("MY_NEW_WINDOW\0".as_ptr()); let _style = CS_HREDRAW | CS_VREDRAW; // https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/UI/WindowsAndMessaging/struct.WNDCLASSA.html // ■ WNDCLASSA ... windows::Win32::UI::WindowsAndMessaging::WNDCLASSA let wc=WNDCLASSA{ hCursor :_hCursor, hInstance: _hInstance, lpszClassName: _lpszClassName, style: _style, lpfnWndProc: Some(wndproc), ..Default::default() }; // ■ windows::Win32::UI::WindowsAndMessaging::RegisterClassA let atom = RegisterClassA(&wc); debug_assert!(atom != 0); let nullptr: Option<*const ::core::ffi::c_void> = None; // ■ windows::Win32::UI::WindowsAndMessaging::CreateWindowExA // ■ PCSTR ... windows::core::PCSTR // ■ windows::Win32::UI::WindowsAndMessaging::WS_OVERLAPPEDWINDOW // ■ windows::Win32::UI::WindowsAndMessaging::WS_VISIBLE // ■ windows::Win32::UI::WindowsAndMessaging::CW_USEDEFAULT CreateWindowExA( Default::default(), _lpszClassName, PCSTR::from_raw("This is a sample window\0".as_ptr()), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 700, 600, None, None, _hInstance, nullptr, ); // ■ windows::Win32::UI::WindowsAndMessaging::MSG let mut message = MSG::default(); // ■ windows::Win32::UI::WindowsAndMessaging::GetMessageA // ■ windows::Win32::UI::WindowsAndMessaging::DispatchMessageA // ■ HWND ... windows::Win32::Foundation::HWND while GetMessageA(&mut message, HWND(0), 0, 0).into() { DispatchMessageA(&mut message); } } return 0; }
先のプログラムのget_randomを以下のように変える(minは使わないことにした)と、乱数の分布が変わったのがわかる。
/////////////////////////////////////////////// /// 正規分布の乱数を生成する /////////////////// fn get_random(count:i32, max:i32) -> Vec<i32>{ use rand::prelude::{Distribution, thread_rng}; use rand_distr::Normal; let mut rng = rand::thread_rng(); // 平均値と標準偏差を用いた乱数生成器を作成 let normal = Normal::new( (max as f32) / 2.0, // 平均 (max as f32) / 8.0 // 標準偏差 ).unwrap(); let mut rlist:Vec<i32> = Vec::new(); for i in 0..count{ let randint:i32 = normal.sample(&mut rng) as i32;// 平均値と標準偏差で乱数生成 rlist.push(randint); } return rlist; }
シードを指定する場合、以下のように[u8;32]の配列をシードとして与える。シードだけで32byteも与えなければならない。なお[0;32]の配列指定で要素の型がu8に定まるのは、文脈的にseedがfrom_seedで与えられていることからデータ型を推論しているかららしい。
fn main() { use rand::Rng; // 乱数を使うためにrand::Rngを使用 use rand::SeedableRng; // シードの指定に必要 use rand::rngs::StdRng; // シードの指定に必要 let seed = [0; 32];// 全要素0、要素数32,u8型の配列を作成 let mut rng:StdRng = SeedableRng::from_seed(seed); // シードを固定した乱数生成器を初期化 //let mut rng = rand::thread_rng(); // シード未指定の場合 let min:i32 = 0; let max:i32 = 20; // 50回ループ (0..50).for_each(|_|{ let randint:i32 = rng.gen_range(min..max);// 最大・最小を指定して乱数を生成 println!("{}",randint); }); }