第19回 乱数

言い訳キーボードでは文章を適当に選ぶ必要があります。今回は、適当に何か選ぶスケッチの作成方法について習得します。

目次

乱数

Arduinoでは、適当な数字を選んでくれる関数が用意されています。

例えば1から6までの適当な数字を選んでもらえれば、サイコロを使ったゲームを作ることができます。

この関数を使えば、言い訳キーボードのスケッチで、例えば1〜3までの適当な数字を選んでもらって、ifswitchを使用して数字に応じた文字列を選ぶ、ということもできます。

このように適当な数字を得ることができればゲーム性のあるスケッチを作ることができますね。


ところで「適当な数字選ぶ」といっても、実際にどのような動きがよくわからないですよね。

もう少し具体的に説明すると、Arduinoでは「いくつからいくつまでの数字を適当に選んでください」という関数が用意されています。(「いくつ」は関数の引数で指定します)

例えば「1〜9までの数字を適当に選んでください」という関数を実行すると、「3」や「7」など、その関数を実行するたびに適当な数字を選んでくれます。

このような適当な数字のことを「乱数」と呼んでいます。

関数を実行するたびに毎回異なる適当な数字が選ばれるので、乱れた数という意味合いでしょうかね。(適当な数なので「適当数」の方が合ってるような気もしますが…)

この関数を使って「乱数」を作ることを、「乱数を生成する」とか「乱数を発生させる」などと言うことがあります。

ところで「乱数」は英語で「Random Number」です。

「Random」(ランダム)は「無作為」とか「行き当たりばったり」というような意味ですが、日本語でも「ランダム」というのはたまに耳にしますので、馴染みがあるかもしれませんね。

それでは、これからこの乱数を生成する方法とその特徴について詳しくみていくことにしましょう。

random関数

乱数を発生するために、Arduinoではrandom関数が用意されています。

この関数の引数の書き方は2通りありますので、それぞれ説明します。

❶ 最小値と最大値を指定する方法

最初の引数指定方法は、生成する乱数の最小値と最大値を指定する方法です。

このように関数を呼び出すと「最小値から(最大値-1)の乱数」を生成してくれます。生成される乱数は整数(int32_t型・long型)です。

ちょっとややこしいのですが、引数は「最大値」となっていますが、この関数が生成する乱数は「最大値−1」まで、という点に注意してください。

例えば、次のスケッチではnumberという変数には「1〜9」までのいずれかの数字が代入されます。(「1〜10」ではないので、スケッチを書くとき間違えそうですよね…)

int32_t number;

number = random(1, 10);

❷ 最大値のみ指定する方法

次に、もう一つの書き方は、最大値のみを指定する方法です。

この書き方は、最小値を省略した状態になっています。

最小値を省略した場合、最小値は0として扱われます。

次のスケッチでは、0から9までの整数がnumberに代入されます。

int32_t number;

number = random(10);

どちらの書き方も、「最大値−1」までの整数になる点に注意しましょう!(正直に言いますと、最大値の指定はよく間違えます…)


それでは実際に乱数を発生させてみましょう!

乱数を表示する

乱数の発生方法が分かりましたので、さっそくスケッチを作成して試してみましょう!

まずは、「0〜9の乱数を30個生成する」スケッチを作成してみます。生成したスケッチはシリアルモニタに表示します。

/*
 * random関数の動作確認用スケッチ
 *   0〜9の乱数を30個生成してシリアルモニタに表示する
 */

void setup() {

  // シリアルモニタ初期設定
  Serial.begin(9600);
  while(!Serial){  
  }

  // 乱数を30個生成してシリアルモニタに表示する
  for(uint8_t count=0; count<30; count++){
    Serial.println( random(10) );
  } 

}

void loop() {

}

お手元にブレッドボードがあれば、一緒に試してみてください。

書き込みが終わると、次のように生成した30個の乱数がシリアルモニタに表示されます。

結果を見ると、確かにランダムな数字、という感じですよね。

この数字をもう少し詳しく確認してみましょう。

実際にArduino Microで試された場合、シリアルモニタに表示されいる数字をテキストエディタなどにコピペして記録しておいていただければと思いま。

予測ができる乱数?

それではもう一度、Arduino Microに乱数を生成してもらいましょう。

シリアルモニタに先ほどの乱数が表示されたまま、再度スケッチを実行してしまうと、現在の状態に続けて表示されてしまいます。

区切りがわからなくなってしまいますので、一度シリアルモニタの表示内容を消去しておきましょう。

シリアルモニタ領域の右上に、シリアルモニタに表示されている内容を消去するボタンがあります。クリックすると表示内容が消去されます。


それでは、再度スケッチを実行して乱数を生成してもらうために、Arduino Microをリセットします。

Arduino Microは次の場所にリセットスイッチがありますので、一度スイッチを押してください。

リセットスイッチ

しばらく待っていると、シリアルモニタに乱数が表示されます。

シリアルモニタに表示された乱数を確認してみましょう。先ほどコピペしておいた乱数と、今回生成した乱数を比較してみてください。

参考に、私の方で実際に3回乱数を生成してみました。結果は次のようになりました。

生成した乱数の比較

確かに1回目は予測できない30個の数字が表示されたと思っていましたが、2回目と3回目もまったく同じ数字じゃないですか!

これって乱数っていうのでしょうか???

毎回同じ数値が表示されるというのでは、乱数としては使えない感じですよね…

これはどういうことなんでしょうか?

擬似乱数

コンピュータは厳密な計算を行う機械です。ランダムな数字を生成する、ということは原理的にはできません。

そのため、コンピュータは乱数を「計算して」生成しています。といっても意味がよくわからないですよね。

そこで、コンピュータが乱数をどのように生成しているのか、具体例で説明します。(この具体例は、説明を簡単にするための一例で、実際の乱数の生成方法もっと複雑になっています)


乱数を生成するには、はじめに最初の数字を決めます。ここでは5とします。これが一つ目の乱数です。(最初の数は適当に決める必要があります)

最初の数字を決めたら、次の数式を使って次の数字を決めます。

次の数字 = ( 3 × 今の数字 + 5 ) を13で割った余り

今の数字は5ですので、(3 x 5 + 5)を13で割った余りで7になります。これが二つ目の乱数です。

次にこの数字を使って先ほどと同じ数式で次の数字を決めます。

今の数字は7ですので、( 3 x 7 + 5 )を13で割ったあまりで、0になります。これが三つ目の乱数です。

この後は上の式を使って次々に数字を計算していきます。

このように計算していくと、

5、7、0、5、7、0…

ちょっとだけ乱数っぽい数字が得られます。

ただこの数字ですと0、5、7以外の数字は出てきませんし、たった3つの数字のパターンの繰り返しになってしまっています。

乱数とは程遠いですが、原理的にはこのような手順で乱数を計算して生成しています。

実際の乱数生成に使われる計算式は、すべての数字がなるべくランダムにあらわれるように、かつパターンがなるべく長くなるように複雑な計算式を使います。(実際の乱数もパターンが繰り返しになっています)

手順をまとめると、コンピュータの世界では、以下の手順で計算して乱数を生成しています。

  1. 最初の数字を決める
  2. 計算式を使用して❶で決めた数字から次の数字を計算する
  3. 計算式を使用して❷の結果から、次の数字を計算する
  4. 計算式を使用して❸の結果から、次の数字を計算する
  5. 以下繰り返し

この仕組みは、Arduinoに限らず、どのプログラムミング言語、どのコンピュータでもこのような「なんちゃって乱数」を生成しています。

ただ「なんちゃって乱数」という呼び方はどうか、ということで正式には「擬似乱数」と呼んでいます。

randomSeed命令

ここまでの説明で、コンピュータは乱数を計算で生成するため、毎回同じパターンになることがわかりました。

「このような仕組みなんです」と言われても、毎回同じ組み合わせの数字は困りますよね。

例えばArduino Microで、じゃんけんゲームやおみくじを作る場合、初めてゲームをする場合はいいとして、何度もやると同じパターンがバレてしまいゲームになりません。

これはなんとか解決する必要があります。

当然ながらArduinoに限らずコンピュータの世界ではこの問題を解決する関数が用意されています。

この関数を説明する前に、この問題を解決する原理を説明します。


先ほど、乱数を発生させる方法として数式を使う説明をしました。その手順では、最初の手順で数字を決めましたよね。

この最初に数字を違うものにすると、その後計算される数字は異なってきます

先ほどの例では最初の数字を5にして計算しました。最初の数字が5の場合、生成される乱数(?)は、5、7、0の繰り返しでした。

この最初の数字を8に変えて計算式で計算すると、結果は「8、9、2、1、8、9、2、1…」というように「8、9、2、1」というパターンの繰り返しになります。

つまり最初の数字を変えるとその後に生成される乱数は変わってくるわけです。


コンピュータの世界ではこのように乱数を計算するときの最初の数字を指定する関数が用意されています。

この「最初の数字」は、これから生成する乱数のおおもとになるため「Seed」(シード)と呼ばれています。日本語では「種」という意味になり、この種を元にこの後の乱数を育てていく、というようなイメージでしょうか。

また、シードを指定することを「乱数の初期化」とも呼ばれます。


Arduinoでは乱数を初期化するために次の関数が用意されています。

randomSeed関数の引数に数字を指定すると、乱数を計算するときの初期値(シード)を変更することができるわけです。


これで違うパターンの乱数を生成することができる!となりそうですが、実はまだちょっと問題があります。

例えば先ほどのスケッチで、違うパターンの乱数を生成しようとして、次のように初期値を35で初期化してみます。(setup関数のみ掲載しています)

void setup() {

  // シリアルモニタ初期設定
  Serial.begin(9600);
  while(!Serial){  
  }

  // 乱数の初期値を変更する
  randomSeed(35);

  // 乱数を30個生成してシリアルモニタに表示する
  for(uint8_t count=0; count<30; count++){
    Serial.println( random(10) );
  } 

}

これで乱数のパターンを変更することができますが、よく考えてみると、Arduino Microが動作するたびに「初期値を35とするパターンの乱数」が毎回生成されてしまいます

結局毎回同じ乱数になってしまう、という状況に陥ってしまいます。


この問題を解決するには、randomSeed命令の引数は適当な数字にする必要があります

適当な数字が必要なためにrandom関数を使うわけですが、そのために適当な数字が必要という状況になつてしまいました。

この問題を解決するにはどうすればいいのでしょうか?


ちょっとくどい説明になってしまいますが、例えば次のようにrandomSeed関数の引数を適当な数値にするため、引数にrandom関数を使うのはどうでしょうか。

randomSeed( random(10) );

この場合、random(10)は毎回必ず同じになってしまいます。(先ほど実際のArduino Microで確認したように、最初の数字は必ず7になります)

ということは、このようなスケッチでは、randomSeed関数で初期値を必ず7に設定することになりますので、結局は毎回同じパターンの乱数になってしまいます。


とても解決できなさそうですよね。

実はArduinoでは、定番の乱数初期化方法があるんです。

この方法については、新しい関数が必要になりますので、次回の記事で詳しく説明します。

【補足】真の乱数

Arduino、というよりコンピュータが発生する乱数は擬似的なもので、真の乱数ではないことがわかりました。

ところで、何かの実験をしたりシミュレーションをするとき、真の乱数(本当にバラバラの乱数)が必要なケースってありそうですよね。

そのような場合は、乱数を発生させる機器を使用することが多いようです。

本当にバラバラな乱数を作るというのは意外に難しく、必ずパターンが出てきてしまったり、かたよりが出てきてしまいます。

そこで、多くの企業や研究機関によって、本当の乱数を発生する機器が日々研究されています。


ところで真の乱数を生成する機器は自然現象を利用するケースが多いようなのですが、研究により不思議な現象も確認されています。

不思議な現象というのは「人間の意識が乱数発生器に影響を与える」というものです。

都市伝説っぽい話ですが、この現象については、優秀な研究者を多く輩出している、かの有名なプリンストン大学で長年研究されています。「WIRED」という雑誌のサイトに記事がありますので、ご興味があればご覧ください。

「心が機械に影響を与える」プリンストン大学の研究

また、現在でも研究が続けられていて、その様子はプリンストン大学のサイトで公開されています。以下のサイトでは、世界の各所に設置されている乱数発生器で生成される乱数に人間の意識がどの程度作用するのか、リアルタイムで公開されています。

The Global Consciousness Project Meaningful Correlations in Random Data

ということで、本当に本当の乱数を発生させる、というのはこの宇宙では無理なのかもしれないですね。

更新履歴

日付内容
2021.10.24新規投稿
2025.2.17random関数の説明内容変更
Arduino IDE2対応
通知の設定
通知タイミング
guest
0 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
目次