pythonで真性乱数を使う。


真性乱数を取り出すpythonのモジュールです。

コンピュータで使える乱数は、２種類あり、周期をもつ疑似乱数と、TRNGから得られる真性乱数があります。他に、「完全乱数」というものも存在し、確率的にしか扱うことは出来ません。つまり、完全乱数はイデア界にしか存在しません。

python3では、乱数の利用は主にrandomモジュールを使いますが、これは、疑似乱数を発生するもので、真の乱数ではありません。しかし、Linuxは、/dev/randomを提供していて、これを読み出すと、環境ノイズからの真性乱数を得ることができるので、これを使います。

「真性乱数」は「完全乱数」と定義が違います。

・真性乱数とは、原理的に予測不能で真に無秩序な乱数。コンピューターによって算術的に生成する疑似乱数に対していう。放射性元素の崩壊など、量子的なふるまいを利用する物理乱数が知られる。真乱数。- 小学館 - デジタル大辞泉より。

・完全乱数とは、完全にでたらめな順番で発生する数値の列を指し、理想の乱数とも呼ばれます。確率的にしか扱うことができません。 - Search Labs | AIによる。

定義が違いますが、真性乱数を完全乱数と看做して、同様に扱って良いでしょう。

完全乱数はユングの共時性（因果律を超えた奇妙な偶然の一致）があるので、EPRパラドックスがEPR相関になったこともあり、現実世界で作るのは困難もしくは不可能かもしれません。真性乱数が完全乱数か否かであるかは、yes/noの2つの答があります。

「数学的に完全な乱数（真の乱数）」を発生させる方法は、数学だけでは原理的に不可能とされ（数学アルゴリズムは決定論的なので）、まだ見つかっていません。しかし、ある日、天才が現れ、無限を包含させ、実現させるかもしれません。

/dev/randomは一回の読み出しで1バイトを返します。

### メソッドの説明

rand(n)はn*8ビット正の整数の範囲の真性乱数を返します。

rand_f(n)は、実用的に、[0,1)のfloat型の乱数を返しますが、分布は実数のように連続ではありませんので、真性乱数ではなくなっています。

randomint(k,n)は、実用的に0~n-1の整数乱数を返しますが、剰余計算を行っているため、真性乱数ではなくなっています。

```truerand.py
#!/usr/bin/python3
#
# truerand.py
# pythonで、/dev/randomからの真性乱数を利用して乱数を発生するモジュール
#
import os
import binascii

# n byteのRAND_MAXを返す関数
# in : n バイト長
# out: nバイトのRAND_MAX
def rand_max(n):
    v=0
    for i in range (0,n):
        v=v*256+0xff
    return(v)

# n byte の真性乱数を返す関数
# parameter : n バイト長
# return    :   n バイトの正の整数の乱数
def rand(n):
    f=open("/dev/random",'rb') # /dev/randomを開く
    randomdata=f.read(n) # nバイト読み出し
    f.close() # /dev/randomを閉じる
    randomhex=binascii.hexlify(randomdata) #１６進の文字列に変換
    randomint=int(randomhex,16) # 整数に変換
    return(randomint)

#
# n byte の精度の[0,1)の実数乱数を返す関数
# parameter : n バイト長
# return    : [0,1)の乱数
#
# 注:割り算を使っているので本当の真性乱数ではない
#
def rand_f(n):
    return(rand(n)/rand_max(n))

#
# 0〜k-1の乱数を返す関数
# parameters : n バイト長
               k 整数
# return     : 0〜(k-1)の整数乱数
#
# 注:剰余演算を使っているので本当の真性乱数ではない
#
def randomint(k,n):
    return(rand(n)%k)

if __name__=="__main__":
    b=8
    times=20
    print(f"{b*8}bit正の真性整数乱数")
    for _ in range(times):
        print(rand(b),end=" ")

    print("")
    print("実数[0,1)の範囲の実数乱数")
    for _ in range(times):
        print(rand_f(b),end=" ")
    print("")
    print("整数0〜99の乱数")
    for _ in range(times):
        print(randomint(100,b),end=" ")
    print("")

```

# 実行結果

```
$ truerand.py
64bit正の真性整数乱数
3307504999628493041 16833230142106673071 12617132537912657723 13507463181985722647 10497082142665300591 6631042183926931135 15360962062758597424 13993642308568418315 766978283825206867 10039168542496294747 5012398474653242549 2895278196839792201 14818507220427785701 12973819612571874604 745060180634753097 3407469691878957494 16057494043478543453 17702076263089849866 6044349191818680689 18016755088876227617 
実数[0,1)の範囲の実数乱数
0.7974003807166161 0.41979958470339007 0.5609974574080073 0.867573227719673 0.4440622865950301 0.6675132571776963 0.6540182828071875 0.3561816976682385 0.8544635154444369 0.14384499913999788 0.6299092884789043 0.8762444099735378 0.12412862806208831 0.9767549851060453 0.7885647613995059 0.20188391849163984 0.42782772905419625 0.10491103155813546 0.8019370785707318 0.43197777323789693 
整数0〜99の乱数
70 33 45 38 39 88 79 9 90 38 36 43 5 49 74 81 56 71 31 29 
$
```