コンピュータは、どこからともなく根拠のない乱数を作成しません。最も可能性が高いのは、時間はランダム性の普遍的な根拠です。
次のルールで乱数を作成するコードを作成してください。
- プログラムのどの時点でも、時間を基準にすることはできません。
- 定義済みのランダム/疑似ランダム関数は使用できません。
- 生成される数値は任意の範囲にすることができます。少なくとも2つの異なる整数:D
- 数値はエコーされます。
コンピュータは、どこからともなく根拠のない乱数を作成しません。最も可能性が高いのは、時間はランダム性の普遍的な根拠です。
次のルールで乱数を作成するコードを作成してください。
回答:
それは楽しかった!
arr = []
index = 0
function init(seed) {
index = 0
arr[0] = seed
for (var i = 1; i < 624; i ++) {
arr[i] = (1812433253 * (arr[i-1] ^ (arr[i-1] >>> 30)) + i) | 0
}
}
function getNumber() {
if (index == 0) generateNumbers()
var y = arr[index]
y ^= (y >>> 11)
y ^= ((y << 7) & 2636928640)
y ^= ((y << 15) & 4022730752)
y ^= (y >>> 18)
index = (index + 1) % 624
return y
}
function generateNumbers() {
for (var i = 0; i < 624; i ++) {
var y = (arr[i] & 0x80000000) + (arr[(i+1) % 624] & 0x7fffffff)
arr[i] = arr[(i + 397) % 624] ^ (y >>> 1)
if (y % 2 != 0) arr[i] ^= 2567483615
}
}
// let's get our seed now from the SE API
var x = new XMLHttpRequest()
x.open('GET', 'http://api.stackexchange.com/2.2/answers?pagesize=10&order=desc&sort=activity&site=stackoverflow&filter=!Sri2UzKb5mTfr.XgjE', false)
x.send(null)
// we've got the answer data, now just add up all the numbers.
// only 4 digits at a time to prevent too big of a number.
var seed = 0
var numbers = x.responseText.match(/\d{0,4}/g)
for (var i = 0; i < numbers.length; i++) seed += +numbers[i]
init(seed)
for (var i = 0; i < 10; i++) console.log(getNumber())
Mersenne TwisterはJSで書きました。そして、どこかから種を手に入れなければならないことに気づきました。
それで、Stack Exchange APIから取得することにしました。(localStorageカウンターを使用してインクリメントすることはできますが、それはおもしろいことではありません。)そのため、最近アクティブだった10個の回答を取得し、応答内の連続する4桁以下をすべて取り、それらを合計しました。
Stack Overflowは常に更新されているため、これらのシードは常に異なります(そして私の割り当ては減少し続けます!)数値には、回答ID、質問ID、スコア、アップ/ダウン投票数、所有者の担当者/ ID、およびラッパーデータ(クォータなど)が含まれます)。1回の実行で256845、それ270495から、それから256048等々...
これにより、ランダムな32ビットの2の補数10個がコンソールに記録されます。出力例:
247701962
-601555287
1363363842
-1184801866
1761791937
-163544156
2021774189
2140443959
1764173996
-1176627822
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
/**
*
* @author Quincunx
*/
public class NoTimeRandom extends Random {
private AtomicLong seed;
public NoTimeRandom() {
byte[] ba = (new String[0].toString() + new String[0].toString()
+ new String[0].toString() + new String[0].toString()
+ new String[0].toString() + new String[0].toString()).getBytes();
int seed1 = 1;
for (byte b : ba) {
seed1 += b;
}
ba = (new String[0].toString() + new String[0].toString()
+ new String[0].toString() + new String[0].toString()
+ new String[0].toString() + new String[0].toString()).getBytes();
long seed2 = 1;
for (byte b : ba) {
seed2 += b;
}
seed = new AtomicLong(seed1 ^ seed2);
}
@Override
protected int next(int bits) {
long oldseed, newseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
newseed = (oldseed * 25214903917L + 11) & 281474976710655L;
} while (!seed.compareAndSet(oldseed, newseed));
return (int) (newseed >>> (48 - bits));
}
public static void main(String[] args) {
Random r = new NoTimeRandom();
for (int i = 0; i < 5; i++) {
System.out.println(r.nextInt());
}
}
}
魔法はにありpublic NoTimeRandom()ます。文字列にキャストされた配列は、数値がランダムであるため、新しいプログラマーを混乱させる可能性があります。(のサンプルchar[]:[C@4a8e91eb)。next方法は以下からコピーされますjava.util.Random。
出力例:
134277366
467041052
-555611140
-1741034686
1420784423
このrngの有効性をテストしてみましょう。
するために私の答えベル曲線を近似、私が使用したデータの生成が良いRNGに依存します。これをrngとして実行してみましょう。出力:

考えた通り。これはかなりお粗末なrngです。
-pthreadフラグ(またはコンパイラーが使用するもの)を使用してコンパイルします。
#include <stdio.h>
#include <pthread.h>
#define m (unsigned long)2147483647
#define q (unsigned long)127773
#define a (unsigned int)16807
#define r (unsigned int)2836
static unsigned long seed;
pthread_t t[20];
int lo, hi, done;
void *pseudorandom(void *id)
{
while(done)
{
int test;
hi = seed/q;
lo = seed%q;
test = a * lo - r * hi;
if (test > 0) seed = test;
else seed = test + m;
}
}
main()
{
int i;
seed = 54321;
done = 1;
for(i = 0; i < 20; i++)
{
pthread_create(&(t[i]), NULL, &pseudorandom, NULL);
}
for (i = 0; i < 10; i++)
{
printf("%lu\n", seed);
}
done = 0;
}
これが「時間は許可されていません」という基準に基づいているかどうかはわかりません。これは、スケジューラを意図的にスレッドセーフティを無視してエントロピーのソースとして使用しているためです。これは、ハードコードされた初期シードでかなり基本的な疑似乱数関数(レーマー乱数発生器)を使用することで機能します。次に、20のスレッドを開始し、すべてのスレッドが共有変数セットを使用してレーマー計算を実行します。
かなりうまく機能しているようですが、ここにいくつかの連続した実行があります:
comintern ~ $ ./a.out
821551271
198866223
670412515
4292256
561301260
1256197345
959764614
874838892
1375885882
1788849800
comintern ~ $ ./a.out
2067099631
953349057
1736873858
267798474
941322622
564797842
157852857
1263164394
399068484
2077423336
編集: これをもう少し考えて、これはまったく時間ベースではないことに気づきました。完全に確定的なスケジューラを使用しても、エントロピーはタイムスライスからではなく、システムで実行中のすべてのプロセスのロードから発生します。
編集2 ベルカーブを投稿する@Quincunxからインスピレーションを得た後、12MBのランダムさをファイルにダンプし、それをCAcertにアップロードしました。ダイハードテストのすべてに失敗しましたが、ENTテストでは8点からかなりの7.999573を記録しました(潜在的決定論のみ)。不思議なことに、スレッド数を2倍にすると悪化します。
を使用してhttps://stackoverflow.com/questionsからシードを取得することにより、0〜255の範囲の乱数を生成しますwget。
#include <stdio.h>
main()
{
FILE *file;
unsigned char c,x;
system("wget -O - https://stackoverflow.com/questions > quest.html");
file = fopen ("quest.html", "r");
while(c=fgetc(file) != EOF) x+=c;
fclose(file);
printf("%d",x);
}
サンプルの実行:
C:\Users\izabera>random
--2014-03-02 16:15:28-- https://stackoverflow.com/questions
Resolving stackoverflow.com... 198.252.206.140
Connecting to stackoverflow.com|198.252.206.140|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 85775 (84K) [text/html]
Saving to: `STDOUT'
100%[======================================>] 85,775 40.3K/s in 2.1s
2014-03-02 16:15:31 (40.3 KB/s) - `-' saved [85775/85775]
15 /* <=================== THIS IS THE RANDOM NUMBER */
C:\Users\izabera>random
--2014-03-02 16:15:36-- https://stackoverflow.com/questions
Resolving stackoverflow.com... 198.252.206.140
Connecting to stackoverflow.com|198.252.206.140|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 85836 (84K) [text/html]
Saving to: `STDOUT'
100%[======================================>] 85,836 50.0K/s in 1.7s
2014-03-02 16:15:38 (50.0 KB/s) - `-' saved [85836/85836]
76
C:\Users\izabera>random
--2014-03-02 16:15:56-- https://stackoverflow.com/questions
Resolving stackoverflow.com... 198.252.206.140
Connecting to stackoverflow.com|198.252.206.140|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 85244 (83K) [text/html]
Saving to: `STDOUT'
100%[======================================>] 85,244 36.0K/s in 2.3s
2014-03-02 16:15:59 (36.0 KB/s) - `-' saved [85244/85244]
144
#include<iostream>
int main()
{
int *ptr=new int,i=0;
for(;i<5;i++)
{
std::cout<<*(ptr+i)<<'\n';
}
return 0;
}
5つの乱数
3つのサンプル
11230576, 0, 11206992, 0, 2053725299、それは私にはランダムではないようです。
インターネットを介して種を入手することで、このごみは何ですか?私をだましているように聞こえます;-)私は代わりに暗号化ハッシュ関数にシードを与え、0から2 ^ 160-1の範囲の出力を与えることを好みます:
use Digest::SHA1 qw(sha1);
use bigint;
sub r {
$_ = \3;
/^.*x([0-9a-f]+).$/;
hex((unpack "H*", sha1 "some_salt".$1.$$)[0])
}
print join " ", r'
不確かな品質のエントロピーがあるときはいつでも、それをより定期的に(ただし、品質を向上させないで!)配布する方法は、ここで行ったように、SHA1やMD5などにパイプすることです。ハッシュ前のシードについては、pidとランダム参照のアドレスを使用しました。もちろん、エントロピーを高めるために他の入力を追加することもできます。たとえば、x86ではTSCを使用できます(ただし、perlでのアセンブリコードのインライン化はちょっとしたことなので、スキップしました)。
次のコンピューターの人とは異なる出力が必要な場合は、「some_salt」を好みの文字列に調整してください。または、ミニマリストの場合は省略してください=)
私のソリューションhashCode()はObjectクラスのメソッドを乱用します。
class G22640 {
static class Rand {
public int nextInt() {
return new Object().hashCode();
}
}
public static void main(String args[]) {
Rand r = new Rand();
for (int i = 0; i < 10; i++) {
System.out.println(r.nextInt());
}
}
}
出力例:
31859448
22101035
11593610
4580332
25736626
32157998
3804398
32440180
19905449
2772678
他の回答が解のランダム性を示すことを動機として、私は自分の解を変更して、intによって返された真ん中の16ビットを返すようにしましたObject.hashCode()。
import java.io.*;
class G22640 {
static class Rand {
public short nextShort() {
return (short) ((new Object().hashCode() >> 8) & 0xFFFF);
}
}
public static void main(String args[]) throws IOException {
Rand r = new Rand();
for (int i = 0; i < 10; i++) {
System.out.println(r.nextShort());
}
// generateToFile("random_22640.txt");
}
private static void generateToFile(String fileName) throws IOException {
Rand r = new Rand();
BufferedOutputStream o = new BufferedOutputStream(new FileOutputStream(fileName));
for (int i = 0; i < 10000000; i++) {
int a = r.nextShort();
for (int j = 0; j < 2; j++) {
o.write(a & 0xFF);
a >>= 8;
}
}
o.flush();
o.close();
}
}
19 MBのファイル(10 7 からなるshort)を生成し、それをCACertに送信しました。これは結果のスクリーンショットです(見栄えがするように編集されていますが、数値はそのままになっています)。

エントロピーテストで7.999991を計測し、7つのダイハードテストすべてに合格(?)したので、その結果には驚きました。
ユーザーがマウスを動かすとJavascriptがランダムに生成される
var ranArr=[];
var random=0;
var first=second=0;
function generateR(event) {
ranArr.push(parseFloat(event.clientX+document.body.scrollLeft))
ranArr.push(parseFloat(event.clientY+document.body.scrollTop));
var len=ranArr.length;
for(var i=0;i<len;i++) {
if(i<len/2) {
first+=ranArr[i];
} else {
second += ranArr[i];
}
}
third = second/first;
third = third+"";
console.log(third.substr(5));
}
document.onmousemove=function(event){generateR(event)};
最後の5つのコピーされたデータ:
9637090187003
7828470680762
6045869361238
4220720695015
2422653391073
ルビー
残念ながらMacのみ。私たちは使用sox(...文字列として、エヘン)マイクからバイト、チャンクのMD5を取り、ヘッダーを切り落とす、それを切り刻む、終了(*咳*)のステータスヘッダを得るためにそれを逆引きします、ハッシュから数値以外の文字を破棄し、残りの大まかな整数を一緒に追加0.し、前にaを付け、浮動小数点数に変換します。
間隔でさまざまな長さの浮動小数点数を生成します0..1。
require 'open3'
require 'digest'
class InsecureRandom
def self.random_number
n = self.get_bytes
.map! { |r| Digest::MD5.hexdigest(r) }
.map! { |r| r.gsub(/[a-z]/, '') }
.map!(&:to_i)
.reduce(0,:+)
"0.#{n}".to_f
end
private
def self.get_bytes
Open3.popen3('sox -d -q -e unsigned-integer -p') do |_, stdout, _|
stdout.read(20000).reverse.split('\\').to_a.take(20)
end
end
end
randomish = Array.new(20) { InsecureRandom.random_number }
puts randomish
# >> 0.2333530765409607
# >> 0.17754047429753905
# >> 0.936039801228352
# >> 0.2781141892158962
# >> 0.6243140263525706
# >> 0.1583419168189452
# >> 0.2173713056635174
# >> 0.930577106355
# >> 0.11215268787922089
# >> 0.13292311877287152
# >> 0.14791818448435443
# >> 0.4864648362730452
# >> 0.5133193113765809
# >> 0.3076637743531015
# >> 0.16060112015793476
# >> 0.7294970251624926
# >> 0.18945368886946876
# >> 0.9970215825154781
# >> 0.13775531752383308
# >> 0.5794383903900283
Pythonの簡潔さは驚くべきものです。imgurのランダム画像の使用は明らかに有効ではないため、私はランダム性の優れた情報源、stackoverflowのチャットを使用しました!
import urllib.request
def getrand():
req = urllib.request.Request("http://chat.stackoverflow.com/")
response = urllib.request.urlopen(req)
the_page = str(response.read())
x = 1
for char in the_page:
x = (3*x + ord(char) + 1)%2**32
print(x)
5試行:
3258789746
1899058937
3811869909
274739242
1292809118
本当にランダムではありませんが、これらはどれもランダムではありません。
whatever.com/random
HTTPリクエストを作成する多くの回答を見ましたが、カバーの下には回線上でランダムな数値が渡されるため、無駄に思えます。だから私はより低いレベルでスワイプするコードを書くことにしました:
use IO::Socket::INET;
print ((sockaddr_in(getsockname(IO::Socket::INET->new(
PeerAddr => "google.com", PeerPort => 80, Proto => "tcp"
))))[0]);
理論的には、0..65535の範囲でランダムなポートを提供します。実際には、決して目にすることのない多くのポートが存在するため、分散は完全ではありません。AFAICTは、ポートが開いているリモートホストからエントロピーを取得するために実行できる最小限の作業です。
PS-エラー処理は読者への課題として残されています;-)