TL;DR —
Rndは0以上1未満(1は含まない)の範囲のランダムなSingleを返します。それ 単体では 本当のランダムではありません。マクロを実行するたびに 同じ 並びを再生します。先頭でRandomizeを 一度 呼び、生成器をシステムクロックでシードすれば、実行ごとに違う並びが得られます。loとhiの間の整数にはInt((hi - lo + 1) * Rnd + lo)を使います。
Sub RandomInteger()
Dim n As Long
Randomize ' クロックで一度シードする - Rnd の前に行う
n = Int((6 - 1 + 1) * Rnd + 1) ' 1 から 6 までの整数、サイコロのように
Debug.Print n
End Sub
Rnd、Round、Mod は、単純に見えて鋭い刃を隠している三つ
の計算ツールです。Rnd の刃は、「ランダム」がこちらから頼むまで果たされない約束だということ — だからこ
そ、これほど多くのマクロが毎回 同じ 当選者を選んでしまうのです。
この記事で学べること
- 考え方の軸 —
Rndは真のランダムではなく、シード付き の擬似乱数生成器である - 第一の罠 —
Randomizeがないために毎回同じになる「ランダムな」結果 - 範囲内の整数を得る正しい式、そして人がやりがちな 1 つずれ
- テストやデモのために、意図して同じ並びを 再現する 方法
Rndを完全に避けるべきとき — セキュリティ、そしてワークシートのRandBetween
考え方の軸:Rnd はシード付きで、真のランダムではない
コンピューターは真のランダムを生み出せません。シード(種)から出発して、ランダムに 見える 数を作
り出す式を走らせるだけです。Rnd はそうした擬似乱数生成器の一つです。同じシードを与えれば同じ数の並び
を作ります — 再現性という利点であり、それが起きていると知らなければ罠にもなります。
罠の全体像はこうです。VBA はどのセッションも 同じ 既定のシードで始まるので、ただ Rnd を呼ぶだけのマ
クロは、実行のたびに同一の並びを配ります。
Sub SameEveryTime()
Dim i As Long
For i = 1 To 3
Debug.Print Rnd ' 0.7055475, 0.533424, 0.5795186 ...
Next i ' - 次の実行でも、その次でも同じ 3 つの数
End Sub
だからこそ「ランダムな」抽選が同じ人を選び続け、「シャッフルした」リストが同じ順序で出てくるのです。
Rnd は言われたとおりのことをしているだけ。新しい場所から始めろと、誰も言わなかったのです。
第一の対処:Randomize を、先頭で、一度
Randomize は生成器をシステムタイマーで再シードするので、各実行が違う地点から始まり、並びが実際に変化
します。
Sub DifferentEveryTime()
Dim i As Long
Randomize ' クロックでシードする - 数ごとではなくマクロ全体で
For i = 1 To 3
Debug.Print Rnd ' これで実行ごとに違う 3 つの数
Next i
End Sub
二つの規則が Randomize を正しく振る舞わせます。一度だけ呼ぶこと — マクロの先頭近くで、ループの中
ではなく。速いクロックから繰り返しシードすると、続けて二度 同じ シードを渡してしまい、意味を台無しに
することがあります。そして Rnd の前に呼ぶこと。続く Rnd の呼び出しが引く出発点を、これが決める
からです。ふつうのマクロに必要なのは、先頭の Randomize 一つだけです。
1 つずれずに、範囲内の整数を得る
Rnd は小数を与えますが、たいていは二つの境界の間の整数が欲しいはずです。正しく求める式は覚える価値が
あります。分かりやすい近道のほうが間違っているからです。
n = Int((hi - lo + 1) * Rnd + lo) ' 正しい - lo..hi のすべての値が出うる
n = Int(Rnd * hi) + 1 ' lo が 1 でないと微妙に誤り / 端がずれる
幅の中の + 1 が効いてきます。Rnd は決して 1 を返さないので、これがないと最大値 hi が出ることは決
してありません。Int((6 - 1 + 1) * Rnd + 1) は 1 から 6 まで(両端を含む)を覆います — 公平なサイ
コロです。lo と hi を変えれば、同じ形があらゆる閉区間を覆います。Int と組み
合わせて小数を落とせば、きれいに均等にばらけた整数が得られます。
意図して同じ並びを再現する
Rnd はシード付きなので、その決定論を利点に変えられます。テスト、デモ、あるいは再現したいバグのために、
固定した数 でシードすれば、「ランダムな」データが実行のたびに同一になります。
Randomize 42 ' 同じシード -> 毎回まったく同じ並び
数値引数付きの Randomize は決定論的にシードするので、続く Rnd の呼び出しは同じ並びを再現します。負
の引数付きの Rnd — Rnd(-1) — もあり、これはその数に結び付いた反復可能な並びを再スタートさせます。そ
して Rnd(0) は、単に 直前の 数をもう一度返します。要点は対称的です。結果が実行ごとに違わなければな
らないなら、クロックから Randomize。再現可能でなければならないなら、定数を付けて Randomize。 制御
できないランダムさは、どちらにしてもバグです。
Rnd を使うべきでないとき
Rnd は標本抽出、シャッフル、テストデータの生成のために作られています — 推測できてはならないもののため
ではありません。予測可能な擬似乱数生成器なので、パスワード、トークン、セキュリティコードには 決して
使わないでください。その気になれば、誰かがその出力を再現できます。そうした用途には暗号用の API を使いま
しょう。
そして、セルにランダムな整数を入れるだけなら、ワークシート関数のほうが簡単なことが多いです。
Application.WorksheetFunction.RandBetween(lo, hi) は両端を含む整数を直接返し、Int の式は要りません。
ただし、シートの RAND()/RANDBETWEEN に対する Rnd の本当の利点が一つあります。あちらは 揮発性 で、
編集のたびに再計算されるので、抽出した値が変わり続けます。Rnd はマクロの実行時に一度だけ発火し、数はそ
のまま動きません — 標本を 抽出したうえで固定しておきたい ときに、まさに望むものです。
ExcelMaster の活用
Rnd は、動いているように見える形で失敗します。抽選は走り、数は現れ、そしてあとになって初めて、誰かが
それが前回と同じ数だと気づく — あるいは範囲の最大値が一度も出てこない、あるいは「安全な」コードが簡単に
再現できてしまう、というふうに。
ExcelMaster には、そのランダムさが 何
のため かを伝えられます — 「監査用にランダムな 20 行を選んで」や「各注文にランダムなレビュー担当者を割
り当てて」 — すると、実行が実際に違うものになるよう Randomize でシードし、すべての値に届くよう
Int((hi - lo + 1) * Rnd + lo) の形を使い、「安全」という言葉が出た瞬間に暗号用のソースへ導きます。ブッ
クとコードはあなたの手元に残ります。
よくある質問
VBA の乱数が毎回同じままなのはなぜですか?
Randomize を呼んでいないからです。Rnd はどのセッションも同じ既定のシードから始まるので、実行のたび
に同一の並びを再生します。マクロの先頭近くで、どの Rnd よりも前に Randomize を一度加えれば、生成器
をシステムクロックでシードでき、実行ごとに違う数が得られます。
VBA で二つの値の間の乱数を生成するには?
Int((hi - lo + 1) * Rnd + lo) を使います。たとえば Int((6 - 1 + 1) * Rnd + 1) は 1 から 6 まで
(両端を含む)の整数を返します。幅の中の + 1 は不可欠です — Rnd は決して 1 を返さないので、これが
ないと上限が出ることは決してありません。先に Randomize を呼びましょう。
Rnd と Randomize の違いは?
Rnd は並びの次の擬似乱数を生成します。Randomize は、その並びが始まる シード を設定します。Rnd
は単体では常に同じシードから始まるので、実行ごとに同じ数になります。Randomize(クロックから、あるいは
固定した数から)は、その出発点を変えます。
テストのために毎回同じ乱数の並びを得るには?
定数でシードします — Randomize 42。同じ数値シードは同じ Rnd 値の並びを再現するので、テストやデモを
反復可能にしたいときにまさに望むものです。逆に実行を違うものにしたいときは、引数なしの Randomize(ク
ロックシード)を使いましょう。
VBA の Rnd をパスワードやセキュリティコードに使えますか?
いいえ。Rnd は予測可能な擬似乱数生成器で — その出力は再現できるので — パスワード、トークン、推測できて
はならないものには安全ではありません。標本抽出、シャッフル、テストデータには使い、セキュリティには暗号
用の API を使いましょう。
検証環境
動作確認: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-18.
関連ガイド: VBA Round · VBA Mod · VBA For ループ · VBA WorksheetFunction · VBA Timer
