Xorshift32をRustで実装してみる

Xorshift32をRustで実装してみる

今回は、Rustで色々コード書いてみる一環として、疑似乱数生成法の1つであるXorshiftを実装してみたいと思います。

実装してみるのは32bitのXorshift(下のページのxorshift32)です。

https://ja.wikipedia.org/wiki/Xorshift

まずはC言語でこのコードを動かし、得られた数値を基にRustでテストを書きます。

#include <stdio.h>
#include <stdint.h>

struct xorshift32_state {
  uint32_t a;
};

uint32_t xorshift32(struct xorshift32_state *state)
{
    uint32_t x = state->a;
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    return state->a = x;
}

void main() {
    struct xorshift32_state st = {1};
    for (int i = 0; i < 10; i++) {
        printf("%u\n", xorshift32(&st));
    }
}

このコードを実行して得られる出力は以下の通りです。

270369
67634689
2647435461
307599695
2398689233
745495504
632435482
435756210
2005365029
2916098932

これで、xorshiftを実装した時の正しい値が分かりました。

では次にRustで実装を行います。

まずテストの部分です。

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_xorshift32() {
        let mut rng = Xorshift32::new(1);
        let expected: [u32; 5] = [270369, 67634689, 2647435461, 307599695, 2398689233];
        for e in expected.iter() {
            assert_eq!(e, &rng.next());
        }
    }
}

10個出力しましたが、まぁ5個も確認して合っていれば十分かな、ということで先頭から5個の値をテストします。

では実際のXorshiftの実装をしていきます。以下のような感じで書きました。

pub struct Xorshift32 {
    state: u32,
}

impl Xorshift32 {
    pub fn new(seed: u32) -> Xorshift32 {
        Xorshift32 { state: seed }
    }

    pub fn next(&mut self) -> u32 {
        let mut x: u32 = self.state;
        x ^= x << 13;
        x ^= x >> 17;
        x ^= x << 5;
        self.state = x;
        self.state
    }
}

特に移植で難しい部分もなく書き移せました。では最後にcargo testで確認します。

running 1 test
test tests::test_xorshift32 ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

無事テストが通ったということで、XorshiftをRustで実装することができました。

めでたしめでたし、ということで今回はここまでです。