Home > libalgo > XorShift (Xor128)

XorShift (Xor128)

概要

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

実装

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

#[allow(dead_code)]
impl Xor128 {
    pub fn new() -> Xor128 {
        use std::io::Read;
        let mut buf = [0; 4];
        let mut urandom = std::fs::File::open("/dev/urandom").expect("failed opening /dev/urandom");
        urandom.read(&mut buf).expect("failed reading /dev/urandom");
        let mut seed: u32 = 0;
        for i in 0..4 {
            seed |= (buf[i] as u32) << (4 * i);
        }
        Xor128::from_seed(seed)
    }

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

    pub 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
    }

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

    pub fn next_i32(&mut self, low: i32, high: i32) -> i32 {
        assert!(low <= high);
        low + self.next((high - low + 1) as u32) as i32
    }

    pub fn next_u32(&mut self, low: u32, high: u32) -> u32 {
        assert!(low <= high);
        low + self.next(high - low + 1)
    }

    pub 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])
        }
    }

    pub 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])
        }
    }

    pub fn shuffle<T>(&mut self, values: &mut [T])
    where
        Self: Sized,
    {
        let n = values.len();
        for i in 0..n - 1 {
            let t = n as u32 - i as u32;
            values.swap(i, i + self.next(t) as usize);
        }
    }
}