定番といえば定番ですが、「乱数はどのくらい乱数なのか」です。タイトルを「何処かで見たな…」と思った人は、なかなか通です(笑)
基本的にコンピューターが作成する乱数というのは、ある意味では規則的なものです。たぶん。どのような規則なのかは、さっぱりわかりませんけど。
JavaScriptの時と同じように、「発生する値の分布」を調べてみました。それだけでは面白くなかったので、今回は「似たような値が連続して発生しないか」も調べてみました。ついでに(というか一度やってみたかったので)、結果を見やすくするため、出力をグラフにしてみました。
前者については、ほぼ均等に発生するようです。データ数が多いほどばらつきが少なくなります。
大量発生させるには不安が多いので、ローカルで試した「1,048,576回」の結果を載せておきます。ちなみに、画像は「png形式」です。一度使ってみたかったので…。
で、後者ですが、なかなか面白い結果になりました。
この結果をどう見ます?
と、思ったところで、「差」ではなく「どう動いたか」を見ることにしました。画面からはみ出るので「比率」は表示してませんが、以下の画像がその結果です。
三角ですね(笑)
やってみれば、「あ、そうか」という感じですが、まさかこんな結果になるとは思いませんでした。JavaScriptでも試してみる価値はあるかもしれません。
ソースコード
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
#!/usr/bin/perl
#BEGIN{
# print "Content-type: text/plainnn";
# open(STDERR, ">&STDOUT");
# $|=1;
#}
$usr_title = 'テスト31';
require "tsenv.pl";
$G_image = "/x/nobu3/images/blue1.gif";
{
printHeader($usr_title);
printBodyHeader('<font face=times>Random Test</font>');
srand(time()^($$+($$<<15)));
randomTest(10, 2**4);
randomTest(10, 2**8);
randomTest(10, 2**12);
printFooter();
exit(0);
}
sub randomTest{
my($len, $loopTimes) = @_;
my @value = (); # 発生値格納用
my @near = (); # 発生値差格納用
my $winH = 150; # 縦棒グラフの最大高さ
my $eleW = 40; # 縦棒グラフの各棒の幅
my $winW = 400; # 横棒グラフの最大長さ
my $eleH = 20; # 横棒グラフの各棒の幅
# 配列初期化(無くても動くけど...)
for($i=0;$i<$len;$i++){
$value[$i] = 0;
$near[$i]->[0] = 0;
}
# 移動値用(上に同じ)
# for($i=$len;$i<$len*2-1;$i++){
# $near[$i]->[0] = 0;
# }
# 乱数発生
# 1回目例外処理
my $lst = int(rand(scalar(@value))); # 発生値比較用
$value[$lst]++;
# 2回目以降処理
for($i=1;$i<$loopTimes;$i++){
my $now = int(rand(scalar(@value)));
$value[$now]++;
$near[abs($now-$lst)]->[0]++; # 前回との差をカウント
# $near[$now-$lst+$len-1]->[0]++; # 前回との移動値をカウント
$lst = $now;
}
# 最小値、最大値
my($min, $max) = ($loopTimes, 0);# 最小値、最大値初期化
foreach(@value){
$min = $_ if($_ < $min);
$max = $_ if($max < $_);
}
# 書式設定
my $ws = $max / ($winW - 10); # 横グラフ表示用
my $loopTimesN = divideNum($loopTimes);
my $dif = $max - $min;
my $difN = divideNum($dif);
my $difP = sprintf "%.2f%%", $dif / $loopTimes * 100;
my $maxN = divideNum($max);
my $maxP = sprintf "%.2f%%", $max / $loopTimes * 100;
my $minN = divideNum($min);
my $minP = sprintf "%.2f%%", $min / $loopTimes * 100;
foreach(@near){
$_->[1] = divideNum($_->[0]);
$_->[2] = sprintf "%.2f%%", $_->[0] / $loopTimes * 100;
}
# まとめの出力
Jprint(<<EOM);
<div class=box1>
<strong>データ数:$loopTimesN</strong>
<table border=1>
<tr><th>最大値<td align=right>$maxN<td align=right>$maxP
<tr><th>最小値<td align=right>$minN<td align=right>$minP
<tr><th>誤 差<td align=right>$difN<td align=right>$difP
</table>
<br>
EOM
# 各項目の出力
Jprint(<<EOM);
<table border=1>
<caption>値の発生回数と比率</caption>
<tr>
<th>発生値
<th width=$winW>カウント数
<th>比率
<th>備考
EOM
my $cnt = 0;
foreach(@value){
my $w = int($_ / $ws); # グラフ巾決定
my $n = divideNum($_); # カウント数
my $p = sprintf("%.2f%%", $_ / $loopTimes * 100); # 比率
print <<EOM;
<tr><th>$cnt<td>
<img src="$G_image" width=$w height=$eleH alt="$n"><td align=right>
$p<td>
EOM
if($min == $_){
Jprint('最小');
}elsif($max == $_){
Jprint('最大');
}else{
print "<br>";
}
print "n";
$cnt++;
}
print "</table>nn<br>nn";
# 発生値差
print "<table border=1>n";
Jprint("<caption>前回の発生値との差</caption>n<tr>n");
my $nearmax = 0;
foreach(@near){
$nearmax = $_->[0] if $nearmax < $_->[0];
}
my $hs = $nearmax / ($winH - 10);
Jprint("<th height=$winH>カウント数");
foreach(@near){
my $h = int($_->[0] / $hs);
print qq(<td valign=bottom align=center><img src="$G_image" width=$eleW height=$h alt="$_->[1]">);
}
Jprint("<tr>n<th>前回との差");
for($i=0;$i<$len;$i++){ print "<th>$i" }
# 移動値用
# for($i=-($len-1);$i<$len;$i++){ print "<th>$i" }
Jprint("n<tr>n<th>比率");
print "<td align=right>$_->[2]" foreach(@near);
print "n</table>nn<br>nn";
print "</div>nn";
}
sub divideNum{
my($num) = @_;
1 while $num =~ s/(d+)(d{3})/$1,$2/;
return $num;
}
|