エクセルVBAの数学関数のRnd関数で乱数を取得します。
戻り値を加工して実用できるようにします。特に乱数値の整数化とRandomizeは必須です。
6.5兆通りのパスコードの生成方法も解説しています。
こんにちは、じゅんぱ店長(@junpa33)です。
今回のテーマは、乱数を発生させるVBA関数の「Rnd関数」についてです。
エクセルシートでは、Rand関数としてお馴染みだと思います。
ランダムな結果を出したい時など、意外と利用する機会がある関数ではないかと思います。
コンテンツ
Rnd関数で乱数を取得ーデフォルトの使い方ー
「Rnd関数」は、戻り値として、0 以上 1 未満の値をランダムに返します。
Rnd関数の構文
Rnd関数の構文
- Rnd ( [ 数値 ] )
数値 | 内容 |
---|---|
0未満の数値 | 数値に応じた乱数値を戻す。 数値が同じであれば、何度実行しても戻り値は同じ |
0 | 直前の戻り値と同じ値を返します。 |
省略時または0より大きい数値 | 乱数列から次の乱数値を戻します。 |
乱数の取得と使えない戻り値を加工するコード
Rnd関数の戻り値はそのままでは使いにくい
Rnd関数を扱う上で、素のまま使うには注意点が2つあります。
- 出力される戻り値がそのままでは使いにくい
- 乱数の発生が「シード値」のためにパターン化してしまう。
この2つの注意点を解決しておく必要があります。
- ご覧のようにRnd関数の戻り値は、そのままだと非常に扱いづらい数値になっています。
- エクセルブックを一度閉じて再度起動、このRnd関数を起動したときも、前回のRnd関数と同じ戻り値(結果)になっています。
Option Explicit
Sub Rnd関数テスト1()
Dim i As Long
For i = 3 To 10
Range("B" & i) = Rnd
Next i
End Sub
戻り値を加工。整数値を発生させる
1桁の整数の乱数、2桁の整数の乱数を発生させる方法
整数値に加工するために、「Int関数」を使っています。
Sub Rnd関数テスト2()
Dim i As Long
For i = 3 To 10
Range("B" & i) = Rnd
'1桁の整数の乱数を発生させる
Range("C" & i) = Int(Rnd * 10)
'2桁の整数の乱数を発生させる
Range("D" & i) = Int(Rnd * 100)
Next i
End Sub
- 「Int関数」について詳しくはこちらです。
- 切り上げ切り捨ての「RoundUp関数」「RoundDown関数」についてはこちらをご覧ください。
戻り値を加工。整数にしてかつ乱数値の範囲を設定
指定範囲内での整数値の乱数を発生させる方法
指定範囲内の整数値乱数
- Int (Rnd * (「最大値」-「最小値」+ 1 ) + 「最小値」)
- 5以上15以下の範囲で整数値の乱数を発生させる。
- 25以上50以下の範囲で整数値の乱数を発生させる。
Sub Rnd関数テスト3()
Dim i As Long
For i = 3 To 10
Range("B" & i) = Rnd
'5から15の整数の乱数を発生させる
Range("C" & i) = Int(Rnd * 11 + 5)
'25から50の整数の乱数を発生させる
Range("D" & i) = Int(Rnd * 26 + 25)
Next i
End Sub
戻り値を加工。発生した乱数値を重複させない方法
Rnd関数の戻り値そのままの素だと、同値のものが戻ってくることは稀です。
Int関数で整数値化することで同値になってしまうことがあるということです。
そこで、方法は2つ
Sortメッソドを使って並び順に番号付け
一番最初に、乱数を取得順にID番号を振っていきます。
次に、戻り値を整数化せずに、小→大(または大→小)へ並び替えをし、順位付けをします。
最後に、それをID番号の取得順に並び替えを戻すと、重複のない整数値で乱数を取得した状態になります。
Sortメソッドの構文
- Range ( セル範囲 ) . Sort Key1 := Rangeオブジェクト, Order1 := xlAscending
Rankワークシート関数で乱数値の順位を取得する
エクセルシートで使われているRank関数を、エクセルVBAでも利用します。
この方法だと、重複のない乱数の発生範囲内ですべてではないいくつだけ発生させるということも可能です。
ワークシート関数Rankの構文
- WorksheetFunction . Rank ( 数値 , 参照 , 表示方法 )
「数値」・・・・ 順位付けの対象を指定します
「参照」・・・・ 順位付けの対象範囲
「表示方法」・・・・ 降順表示は0、昇順表示は1を指定します
SortメソッドとRank関数、2つの方法を使った例題
5以上25以下の範囲で、重複しない整数値の乱数を発生させます。
「Sortメソッド」については、21回すべて発生させます。
「Rankワークシート関数」については、全21回中の11回だけ発生させます。
Sub Rnd関数テスト4()
Dim i As Long, j As Long, k As Long
'Sortメソッド利用
'乱数を取得、ID番号を付与
For i = 5 To 25
Range("A" & i - 2) = i
Range("B" & i - 2) = Rnd
Next i
'取得乱数を小さいもの順に並び替え
Range("A3:B23").Sort key1:=Range("B3"), order1:=xlAscending
'乱数の順位付け
For j = 5 To 25
Range("C" & j - 2) = j
Next j
'ID番号で元の状態(取得順)に並べ直し
Range("A3:C23").Sort key1:=Range("A3"), order1:=xlAscending
Range("A2") = "ID番号"
Range("C2") = "Sort利用"
'ワークシート関数Rank利用
For k = 5 To 25
Range("E" & k - 2) = _
WorksheetFunction.Rank(Range("B" & k - 2), Range("B3:B23"), 1) + 4
'乱数を10個だけ取得する時
If k - 2 > 12 Then Exit For
Next k
Range("E2") = "Rank利用"
End Sub
発生させた乱数値をシートセルに表示させずに順位を取得する
エクセルシートを使わずに、発生させた乱数値の順位を取得します。
これまでは、シートのセルに発生させた乱数値を順に表示させて、それらのセルの値に対して整数値化、並び替え、番号付けを行いました。
ここでは、配列変数に発生させた乱数を格納し、乱数値の順位付けを行っていきます。
例えばRnd関数で100個の乱数を発生させると、1から100までの整数値の乱数が同時に発生していることになります。
非常に簡単なVBAコードですが、
乱数発生回数が以下の例のような10万回ともなると、計算処理に時間がかかってしまうこともあります。
基本的に、配列の要素を1つづつ「1対1で」大小比較を行っていきます。
『「調べる要素」ー「それ以外の要素」』を引き算して、差が0より小さければ「それ以外の要素」のほうが大きいことが判明します。
そのケースが何回あるかを計測し、「その回数+1」が「調べる要素」の降順の順位となります。
Rnd関数で10万回乱数を発生させ、最大値(順位1位)が発生したのは何回目かを表示します。
Sub 配列要素から順位を取得()
Dim i, j, k, n, p As Long
Dim V(1 To 100000) As Variant
Dim Rn(1 To 100000) As Long
'10万回乱数を発生させます。配列変数に格納します。
For i = 1 To 100000
V(i) = Rnd
Next i
'要素1対1の比較、カウント。配列変数にカウント数を格納します。
For j = 1 To 100000
n = 1
For k = 1 To 100000
If V(j) - V(k) < 0 Then
n = n + 1
Rn(j) = n
Else
Rn(j) = n
End If
Next k
Next j
'順位1位の出現回を調べる。
For p = 1 To 100000
If Rn(p) = 1 Then
MsgBox "最大値(1位)の出現は" & p & " 回目でした。"
Exit For
End If
Next p
End Sub
- 一次元配列についてはこちらの記事が参考になります。
乱数の発生パターンを回避する。「Randomizeステートメント」
「Randomize ステートメント」をあらかじめ実行しておくことで「シード値」がランダムに変更(初期化)されます。
ザックリと「シード値」とは、エクセルが乱数を発生させるための計算を行う上で、基となるある値のことです。
もし、「Randomize ステートメント」を実行しないと・・・
エクセルの起動時には「シード値」は固定されていますので、毎回同じ乱数の発生結果になります。
同じシード値を指定すると始めから同じ順番で乱数が発生します。
これでは最早、乱数発生とは言い難いですね。
「Randomize ステートメント」の使い方は、いたって簡単です。
記述したエクセルVBAコードの中で、「Rnd関数」が実行される行の前に「Randomize」とだけ記述するだけでOKです。
変数宣言の「Dim」の直後ぐらいに入れておくと間違いないかと思います。
戻り値を乱数表に応用ー6.5兆通りパスコードの生成ー
乱数を取得できるRnd関数を使って、「8桁のパスコード」を作成します。
パスコード生成のためのVBAコード概要
パスコード生成のステップとしては以下のように行います。
8桁のパスコードを作りますので、数学的計算上は、40種の8乗回で約6.5兆通りパスコード強度になります。
実用上、全く問題なく使えるレベルだと思います。
乱数表を準備します
10行・4列合計40セルの乱数表を準備します。
セル内の文字については、並び順は何でも良いです。
ただし、文字の重複がある場合は、パスコード強度が低下します。
乱数表から文字を抽出します
1から40の数字をセル番地に当てはめる方法は、考え方として
列番号は
- 1から10までは、乱数表の1列目
- 11から20までは、乱数表の2列目
- 21から30までは、乱数表の3列目
- 31から40までは、乱数表の4列目
行番号は数字の1桁目の数
- 1,11,21,31は乱数表の1行目
- 2,12,22,32は乱数表の2行目
- 3,13,23,33は乱数表の3行目
- 以降同様
- 10,20,30,40は乱数表の10行目
Sub Rnd関数でパスワード()
Dim i As Long, C As Long, R As Long
Dim Key As Long, KE As String
Dim Word(1 To 40) As String, Pass As String
'乱数発生をパターン化を防止します
Randomize
For i = 1 To 8
'1から10までの整数値に加工します
Key = Int(Rnd * 40 + 1)
'取得した乱数からセル番地を作ります
C = WorksheetFunction.RoundUp(Key / 10, 0) + 1
R = Key Mod 10 + 1
If R = 1 Then R = 11
'[ここから→]
Word(Key) = Cells(R, C)
Pass = Pass & Word(Key)
KE = KE & Key & " , "
'[←ここまで]
Next i
Range("B14") = Pass
Range("B15") = KE
End Sub
説明用にVBAコードを作っています。
実際の使用上は
説明用のこのコードを
Word(Key) = Cells(R, C)
Pass = Pass & Word(Key)
KE = KE & Key & " , "
こちらの1行のコードに変更します。
Pass = Pass & Cells(R, C)
生成したパスコード
実際に動かすとこのようにパスコードを取得できました。
Rnd関数で乱数を取得のまとめ
これまで、Rnd関数の使い方を紹介してきました。
Rnd関数を実用するには、結構なんだかんだとコードを加工しないといけないことをご理解いただけたと思います。
イベント企画案なんかでは、お世話になることも多い関数ですので、
これを機会に是非覚えて行ってください。
抽選会の当選者を決定するときには、このRnd関数をぜひ使いたいと思いますが、
パターンによっては当選確率変更ルールもあったりと、解決にお悩みの方もおられるようです。
解決の提案の記事もUPしています。参考にしてみてください。
無料エクセルVBA抽選ソフト【重複なし】ダウンロードと使い方エクセルVBAを独習するのに参考書は欠かせません。 参考書選びは自分に合った「相棒」にできるものを選んでいきたいです。
エクセルVBAの独習でおすすめ参考書を7冊選ぶ。良書との出会いは大切です今回の記事はここまでです。 最後までご覧いただき有難うございました。
<記事内容についての告知>
VBAコードの記述記事においては、その記述には細心の注意をしたつもりですが、掲載のVBAコードは動作を保証するものではりません。 あくまでVBAの情報の一例として掲載しています。 掲載のVBAコードのご使用は、自己責任でご判断ください。 万一データ破損等の損害が発生しても当方では責任は負いません。
アンケートでポイ活しよう!!
アンケートに答えれば答えるほど ”使える” ポイントがたまります。