スポンサーリンク

Rustで乱数

Rustの乱数の使い方。

サンプルコード

Cargo.toml

乱数を使用するためにはrandクレートを使用する。

[dependencies]
# 乱数を使用 https://crates.io/crates/rand
rand = "0.8.5"

最も基本的なコード

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で二次元にランダムな点をプロット

これだけではさすがにつまらないので、win32apiを使ってSetPixelで点を散布してみる。

以前作ったメモリデバイスコンテキストのコードで乱数のプロットを表示する。

Rust+windows-rsでDIBを使う

winmain.rs

#[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);

    });
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: