🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の Rnd — 乱数、Randomize、そして同じ並びを繰り返す罠

|

Excel VBA の Rnd — 乱数、Randomize、そして同じ並びを繰り返す罠

TL;DRRnd0 以上 1 未満(1 は含まない)の範囲のランダムな Single を返します。それ 単体では 本当のランダムではありません。マクロを実行するたびに 同じ 並びを再生します。先頭で Randomize一度 呼び、生成器をシステムクロックでシードすれば、実行ごとに違う並びが得られます。 lohi の間の整数には 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

RndRoundMod は、単純に見えて鋭い刃を隠している三つ の計算ツールです。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 まで(両端を含む)を覆います — 公平なサイ コロです。lohi を変えれば、同じ形があらゆる閉区間を覆います。Int と組み 合わせて小数を落とせば、きれいに均等にばらけた整数が得られます。

意図して同じ並びを再現する

Rnd はシード付きなので、その決定論を利点に変えられます。テスト、デモ、あるいは再現したいバグのために、 固定した数 でシードすれば、「ランダムな」データが実行のたびに同一になります。

Randomize 42                 ' 同じシード -> 毎回まったく同じ並び

数値引数付きの Randomize は決定論的にシードするので、続く Rnd の呼び出しは同じ並びを再現します。負 の引数付きの RndRnd(-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