ホーム > libalgo

XorShift (Xor128)

概要

現在Rustの標準ライブラリには乱数が無い.

実装

#[allow(dead_code)]
struct Xor128 {
    x: u32,
    y: u32,
    z: u32,
    w: u32,
}

#[allow(dead_code)]
impl Xor128 {
    fn new() -> Xor128 {
        use std::io::Read;
        let mut buf = [0; 4];
        let mut urand = std::fs::File::open("/dev/urandom").unwrap();
        urand.read(&mut buf).unwrap();
        let mut seed: u32 = 0;
        seed |= (buf[0] as u32) << 0;
        seed |= (buf[1] as u32) << 8;
        seed |= (buf[2] as u32) << 16;
        seed |= (buf[3] as u32) << 24;
        Xor128::from_seed(seed)
    }

    fn from_seed(seed: u32) -> Xor128 {
        let mut res = Xor128 {
            x: 123456789,
            y: 987654321,
            z: 1000000007,
            w: seed,
        };
        for _ in 0..10 {
            res.gen();
        }
        res
    }

    fn gen(&mut self) -> u32 {
        let t = self.x ^ (self.x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        self.w = (self.w ^ (self.w >> 19)) ^ (t ^ (t >> 8));
        self.w
    }

    fn next(&mut self, right: u32) -> u32 {
        self.gen() % right
    }

    fn next_in(&mut self, left: i32, right: i32) -> i32 {
        left + self.next((right - left + 1) as u32) as i32
    }

    fn sample<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T>
        where Self: Sized
    {
        if values.is_empty() {
            None
        } else {
            Some(&values[self.next(values.len() as u32) as usize])
        }
    }

    fn sample_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T>
        where Self: Sized
    {
        if values.is_empty() {
            None
        } else {
            Some(&mut values[self.next(values.len() as u32) as usize])
        }
    }

    fn shuffle<T>(&mut self, values: &mut [T])
        where Self: Sized
    {
        let mut i = values.len();
        while i >= 2 {
            values.swap(i, self.next(i as u32) as usize);
            i -= 1;
        }
    }
}