C#とjavascriptで乱数系列を共有したいんだが…（XorShiftを題材として）

# 端的に言ってしまうと…

javascriptでUInt32な数値を扱いたかったんです
ん？
いや、とっ掛かりはやはり`XorShift`な訳で、ある乱数列にデータを重畳してプログラム間で受け渡ししたいな、と
まぁその様に思った次第です

でも今回のプログラム間、ってのが`C# ⇔ javascript`なんです
ここで問題になるのが`javascript`の乱数は`seed`を必要としません、ってか「受け付けません」
それでは乱数列の共有など出来るハズもありませんから、何か`seed`を指定できる簡便な乱数発生器はないかな？

と思って行き当たったのが`XorShift`なんです





# XorShift

これはググって頂ければすぐ分かりますが、すんごい軽量ながら`seed`を元に結構ガチな乱数列を捻り出してくれる（らしい）疑似乱数発生器です

おーっ！
こいつぁ御誂え向き…

なんて思ったのも束の間
そこそこの周期を期待するなら、`unsigned int`な数値を扱える必要があるぅ？

いやいやいやー
御冗談を
`javascript`の扱える数値に型なんて概念ありませんぜ
なんなら、整数と小数どころか数値列と文字列の境だって曖昧だっちゅーの





# 実装（C#）

ま、それはさておき、やってみましょに

まずはC#からですね

```C#
public 	class XorShift {
	private uint t = 0u;
	private uint x = 123456789u;
	private uint y = 362436069u;
	private uint z = 521288629u;
	private uint w = 88675123u;

	public XorShift() { }

	public XorShift(int seed) {
		w = (uint)seed;
	}

	public uint Next() {
		t = x ^ (x << 11);
		x = y;
		y = z;
		z = w;

		w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
		return w - 1;
	}

	public uint Next(uint maxValue) {
		return Next() % maxValue;
	}

	public uint Next(uint minValue, uint maxValue) {
		return minValue + (Next() % (maxValue - minValue));
	}

	public void NextBytes(byte[] buffer) {
		for(int i = 0; i < buffer.Length; i++)
			buffer[i] = (byte)Next(256);
	}

	public double NextDouble() {
		return (double)Next() / uint.MaxValue;
	}
}
```

こんな感じですかね？
`uint`を返してしまう処が本家`Random`と違う処ではありますが、メソッドの構成などは合わせてみました

ここでポイントとなるのは、`Next()`の最後で`w - 1`を返している処ですね
実は問題として指摘されているのが、`XorShift`は`zero`を返さないよね？　と…

うーん、そうなんだー
でも、zeroを返さない（かも知れない）けど、１は返す可能性があるよね？
じゃぁ、１引いちゃえばいいじゃん…
なんてね

実は`NextDouble()`の仕様から考えると、その方が健全かなと云う結論になります
つまり、最後に１を減ずる事で`Next()`の定義域が`0 <= Next() < uint.MaxValue - 1`となって、必然的に`NextDouble()`の定義域は`0.0 <= NextDouble() < 1.0`になる、と云う訳です
逆に云うと、`Next()`は`uint.MaxValue`を返さないよね？
なんですけど、そこは目を瞑る事で７方位は丸く収まるので良いのではないでしょうか

で、実行！

```C#
XorShift rand = new XorShift();
for(int i = 0; i < 10; i++)
	Console.WriteLine(rand.Next().ToString("x08"));

```
みたいな感じで、こう

```text
dca345e9
1b5116e5
951049a9
d88d00af
1ec7825d
8db24145
9af81442
2ac00f2b
0837ad57
17906568
```

これをベースにして`javascript`の実装が同じ乱数列を返せば目的は達成！
と云う事で…





# 実装（javascript）

あ！
ここに来てなんですが、私の云っている「`javascript`」は`windows shell`で使われる方です
`IE`とか`Chrome`とか`Edge`で実行できる方の`javascript`ではなくて…

つまり、ちょっとばかり古い`javascript`と云う事
聞く処に因ると、新しい奴は、`class`定義ができたり、部分的に型の定義ができるらしい…
とか、そんな便利なんじゃない方です

勿論、スクリプトエンジンを指定すれば新しい方で動いたりする訳なんですが、起動時に１枚噛ませないといけなくなるので面倒臭いでしょ？

さて、そんな訳で取り敢えず`C#`を`javascript`に書き直してみる事にしましょうか

```js
var XorShift = function(seed) {
	this.t = 0;
	this.x = 123456789;
	this.y = 362436069;
	this.z = 521288629;
	this.w = seed === undefined ? 88675123 : seed;

	XorShift.prototype.next = function() {
		this.t = this.x ^ (this.x << 11);
		this.x = this.y;
		this.y = this.z;
		this.z = this.w;

		this.w = (this.w ^ (this.w >>> 19)) ^ (this.t ^ (this.t >>> 8));
		return this.w - 1;
	}

	XorShift.prototype.nextDouble = function() {
		return this.next() / 0xffffffff;
	}
}
```

こんな感じ？
（一部のオーバロードは諸事情で割愛しました）

で、実行！

```js
var rand = new XorShift();
for(var i=0; i<10; i++)
	WScript.Echo(rand.next().toString(16));
```

```text
-235cba17
1b5116e5
-6aefb657
-2772ff51
1ec7825d
-724dbebb
-6507ebbe
2ac00f2b
837ad57
17906568
```

う～～～ん…
全然違う、どころかマイナスになっちゃうよ（`uint`であって欲しいのだが…）





# 考察

えーっと、何でうまくいかないか、って云うのを－

> だって、`javascript`は`uint`表現できないんだもん

の一言で片づけるのは安直です

何故なら`javascript`の整数の有効桁数って`53bit`くらいあるんですよ?
高々`32bit`で表わされるビット列を`11bit`程度左シフトしたところで、`msb`まで侵食して符号反転しちゃうとは考えられません
符号は別の論理が働いて反転させられてしまっていると考えるのが合理的です

一つ実験してみましょう

```text
> 0x7fffffff
2147483647

> 0x7fffffff + 1
2147483648

> (2147483648).toString(16)
80000000
>
```

ほら、所謂`int.MaxValue`に`1`を足しても`int.MinValue`にならずに`uint`領域に踏み込んでしまっているでしょ？
工夫すれば`uint`の計算だってできる可能性があるって事じゃないでしょうか？

ところで、さっきの`javascript`の実行結果、よ～く見てみるとマイナス符号が付かない奴は`C#`と結果が一致してますね…
でもマイナスの方は全然違う感じ

お！
そうだマイナス符号付いちゃってるんで、ビット反転してみるってのはどうでしょう？

```text
> (0x235cba17 ^ 0xffffffff).toString(16)
-235cba18

>
```

あれ？
ほぼ同じだ…
あー、`0xffffffff`が符号反転の原因になってるのかなぁ
じゃぁ、取敢えずこう

```text
> (0x235cba17 ^ 0x7fffffff).toString(16)
5ca345e8

>
```

大分近くなった（C#ではdca345e9）
乱数列の正符号側がずっーっと一致しているのと考え合わせると、ビット列は保存されている様です
今回の仮実装での表示の仕方（され方？）が問題なんでしょう

となると、マイナス表示されない様にするにはどうしたら良いか？
を探れば良いと云う事ですね





# ゴールに向けて

んー
肝はやっぱり「符号（サインビット）」かと思います
そもそも`javascript`って`+0`と`-0`が表現できてしまう（らしい）ので、サインビットは数値とは別に存在すると云う事ですよね

で、ここでもう一回テストです

```text
> 123456789 << 1
246913578

> 123456789 << 2
493827156

> 123456789 << 3
987654312

> 123456789 << 4
1975308624

> 123456789 << 5
-344350048

> 123456789 << 6
-688700096

> 123456789 << 7
-1377400192

> 123456789 << 8
1540166912

> 123456789 << 9
-1214633472

> 123456789 << 10
1865700352

> 123456789 << 11
-563566592
```

マイナスになったりプラスになったりしますね
`10進`だと良く分からないので`16進`で表現してみましょうか

```text
> (123456789).toString(16)
75bcd15

> (123456789 << 1).toString(16)
eb79a2a

> (123456789 << 2).toString(16)
1d6f3454

> (123456789 << 3).toString(16)
3ade68a8

> (123456789 << 4).toString(16)
75bcd150

> (123456789 << 5).toString(16)
-14865d60
```

`4ビット`左シフトまではプラスの数値ですが、`5ビット`シフトすると負数になってしまいます
つまり、`4ビット`シフトまでは`32ビット`数値として考えた時の`msb`はゼロなので正数を表しているけど、`5ビット`シフトした時に`msb`に`1`が立ってしまうので負数と認識してしまうのではないでしょうか？
その結果、どこか違う所に管理されている「サインビット」が立ってしまうんじゃないのかなぁ…

と云う事で`75bcd150`の方を左シフトした結果から`5ビット`シフトの数値を考えてみましょう
ここで`javascript`の力を借りてしまうと話がややこしくなるので、手作業です

```text
   7    5    b    c    d    1    5    0
0111 0101 1011 1100 1101 0001 0101 0000
                   <<
1110 1011 0111 1001 1010 0010 1010 0000
   e    b    7    9    a    2    a    0
                   ~
0001 0100 1000 0110 0101 1101 0101 1111
   1    4    8    6    5    d    5    f
                   +1
0001 0100 1000 0110 0101 1101 0110 0000
   1    4    8    6    5    d    6    0
```

シフトしたうえで`2の補数`をとると`5ビット`左シフトの結果と一致しました！
つまり、数値としては`eb79a2a0`として表現されているんですが、サインビットが立っているので表示させると`2の補数`形式で解釈されている、と考える事が出来ます
？？　あれ？　普通じゃん

………

じゃぁ、ビット列としては期待通りになっているけど、何かのタイミングで立ってしまっているどこか違うところにある「サインビット」をクリアすることができれば`uint`の数値として表現してくれるのでは？

！！
ここで閃きました
サインなし右シフトって演算があるじゃないですか！
いや、何の論理的な根拠もないですけど、実験実験

```text
> (123456789 << 5).toString(16)
-14865d60

> ((123456789 << 5) >>> 0).toString(16)
eb79a2a0

>
```

ほら、綺麗に`5ビット`左シフトの結果が得られました
何でこうなるのかは`javascript`の中の人に詳しい説明を聞きたい気分ですが、取敢えず`サインなし0ビット右シフト`を行う事でどっかにあるサインビットはクリアされるようです

ビット列演算の結果は常に保存されていた様なので、`return`の値だけ`uint`補正を掛ければ良い筈





# と云う事で最終結果

```js
var XorShift = function(seed) {
	this.t = 0;
	this.x = 123456789;
	this.y = 362436069;
	this.z = 521288629;
	this.w = seed === undefined ? 88675123 : seed;

	XorShift.prototype.next = function(min, max) {
		this.t = this.x ^ (this.x << 11);
		this.x = this.y;
		this.y = this.z;
		this.z = this.w;

		this.w = (this.w ^ (this.w >>> 19)) ^ (this.t ^ (this.t >>> 8));
		return (this.w >>> 0) - 1;
	}

	XorShift.prototype.nextDouble = function() {
		return this.next() / 0xffffffff;
	}
}
```

結果は、こうなりました

```text
dca345e9
1b5116e5
951049a9
d88d00af
1ec7825d
8db24145
9af81442
2ac00f2b
837ad57
17906568
```

`C#`の結果と合いましたね





# 参考情報

* [JavaScriptの数値型完全理解](https://qiita.com/uhyo/items/f9abb94bcc0374d7ed23)
* [JScriptのREPL作ってみた](http://var.blog.jp/archives/70767794.html)
* [jscreplとはJScriptで作成したreplです](https://ameblo.jp/c-plus-style/entry-11739490176.html)

REPLは役に立ちました