C#で乱数の範囲指定をする方法|Random.Nextの使い方と上限・下限の注意点

はじめに

C#で乱数を扱うときによく使うのが、Randomクラスです。ゲームでサイコロの目を作る、配列やリストからランダムに要素を選ぶ、テストデータをランダムに生成するなど、さまざまな場面で利用できます。

その中でも特に重要なのが、「指定した範囲内で乱数を生成する方法」です。C#ではRandom.Nextを使うことで、整数の乱数に対して下限と上限を指定できます。ただし、Random.Nextには「上限は含まれない」「下限は含まれる」という大事なルールがあります。

たとえば、1〜10の整数をランダムに出したい場合、次のように書く必要があります。

C#
Random random = new Random();

int number = random.Next(1, 11);
Console.WriteLine(number);

Next(1, 10)では10が出ないため、1〜10を出したい場合はNext(1, 11)と書きます。

この記事では、C#で乱数の範囲指定をする基本から、Random.Nextの上限・下限の注意点、小数の乱数、Random.Shared、セキュリティ用途で使うRandomNumberGeneratorまで、初心者にもわかりやすく解説します。

1. C#で乱数の範囲指定をする基本

1-1. Randomクラスとは

Randomクラスは、C#で擬似乱数を生成するためのクラスです。擬似乱数とは、完全な意味でのランダムではなく、一定のアルゴリズムに基づいてランダムに見える数値を生成する仕組みです。

通常のアプリケーション開発では、ゲームの演出、ランダム表示、簡単な抽選、テストデータ作成などに使われます。

基本的には、次のようにRandomのインスタンスを作成して使います。

C#
Random random = new Random();

その後、Nextメソッドを呼び出すことで整数の乱数を生成できます。

C#
int number = random.Next();
Console.WriteLine(number);

Random.Next()は、0以上int.MaxValue未満の整数を返します。より実用的には、範囲を指定して使うケースが多いです。

1-2. Random.Nextで整数の乱数を生成する方法

Random.Nextには複数の使い方があります。代表的なものは次の3つです。

C#
Random random = new Random();

int a = random.Next();
int b = random.Next(10);
int c = random.Next(1, 10);

それぞれの意味は次のとおりです。

C#
random.Next();        // 0以上 int.MaxValue 未満
random.Next(10); // 0以上 10未満
random.Next(1, 10); // 1以上 10未満

ここで重要なのは、指定した上限値は含まれないという点です。random.Next(10)なら、生成される値は0〜9です。10は出ません。

1-3. 範囲指定にはNext(minValue, maxValue)を使う

任意の範囲で整数の乱数を作りたい場合は、Next(minValue, maxValue)を使います。

C#
Random random = new Random();

int number = random.Next(5, 15);
Console.WriteLine(number);

このコードでは、5以上15未満の整数が生成されます。つまり、出る可能性がある値は5〜14です。

minValueは下限、maxValueは上限を表します。ただし、maxValueは含まれません。

C#
random.Next(5, 15);

この場合の範囲は次のようになります。

5, 6, 7, 8, 9, 10, 11, 12, 13, 14

15は出ないので注意しましょう。

1-4. まず押さえるべき基本構文

C#で乱数の範囲指定をするときの基本構文は次のとおりです。

C#
Random random = new Random();

int number = random.Next(minValue, maxValue);

具体例として、1以上100以下の乱数を作る場合は次のように書きます。

C#
Random random = new Random();

int number = random.Next(1, 101);
Console.WriteLine(number);

100を含めたいので、上限には101を指定します。

C#のRandom.Nextでは、基本的に「下限以上、上限未満」と覚えておくと間違いにくくなります。

2. Random.Nextで下限・上限を指定する方法

2-1. 0以上指定値未満の乱数を生成する

Random.Nextに引数を1つだけ指定すると、0以上、その値未満の整数が返されます。

C#
Random random = new Random();

int number = random.Next(10);
Console.WriteLine(number);

この場合、生成される値は0〜9です。

0以上10未満

つまり、10は含まれません。

配列やリストのインデックスをランダムに選ぶ場合、この形式は非常によく使われます。

C#
string[] colors = { "Red", "Blue", "Green" };

Random random = new Random();
int index = random.Next(colors.Length);

Console.WriteLine(colors[index]);

配列のインデックスは0から始まるため、random.Next(colors.Length)と書くことで、0〜colors.Length - 1の範囲を安全に取得できます。

2-2. minValue以上maxValue未満の乱数を生成する

下限と上限を指定する場合は、Next(minValue, maxValue)を使います。

C#
Random random = new Random();

int number = random.Next(10, 20);
Console.WriteLine(number);

このコードでは、10以上20未満の整数が生成されます。

10, 11, 12, 13, 14, 15, 16, 17, 18, 19

20は出ません。

範囲指定の基本は、次のように考えるとわかりやすいです。

random.Next(下限, 上限 + 1)

ただし、これは「上限を含めたい場合」の考え方です。

たとえば、10〜20を含めたい場合は次のように書きます。

C#
int number = random.Next(10, 21);

2-3. 1〜10の乱数を作る場合の書き方

初心者が特に間違えやすいのが、1〜10の乱数を作るケースです。

間違いやすい書き方は次のとおりです。

C#
Random random = new Random();

int number = random.Next(1, 10);

この場合、生成されるのは1〜9です。10は出ません。

1〜10の乱数を生成したい場合は、次のように書きます。

C#
Random random = new Random();

int number = random.Next(1, 11);
Console.WriteLine(number);

Random.Nextの第2引数は「含まれない上限」なので、出したい最大値に1を足す必要があります。

1以上11未満 = 1〜10

サイコロのように1〜6を出したい場合も同じです。

C#
int dice = random.Next(1, 7);

2-4. 負の数を含む範囲を指定する方法

Random.Next(minValue, maxValue)では、負の数を含む範囲も指定できます。

C#
Random random = new Random();

int number = random.Next(-10, 11);
Console.WriteLine(number);

このコードでは、-10以上10以下の整数が生成されます。

-10以上11未満

つまり、出る可能性がある値は-10〜10です。

別の例として、-5〜5の乱数を作る場合は次のように書きます。

C#
int number = random.Next(-5, 6);

負の数を含む場合でも、考え方は同じです。minValueは含まれ、maxValueは含まれません。

2-5. 変数を使って範囲を指定する方法

乱数の範囲は、固定値だけでなく変数でも指定できます。

C#
Random random = new Random();

int min = 1;
int max = 100;

int number = random.Next(min, max + 1);
Console.WriteLine(number);

このコードでは、1〜100の整数が生成されます。

ユーザー入力や設定値を使って範囲を変えたい場合にも便利です。

C#
int minLevel = 5;
int maxLevel = 20;

int enemyLevel = random.Next(minLevel, maxLevel + 1);
Console.WriteLine(enemyLevel);

ただし、max + 1を使う場合は、maxint.MaxValueに近いとオーバーフローに注意が必要です。通常の範囲では問題になりにくいですが、非常に大きな数値を扱う場合は設計を見直しましょう。

3. Random.Nextの上限・下限で注意すべきポイント

3-1. maxValueは含まれない

Random.Next(minValue, maxValue)で最も重要なのは、maxValueが含まれないことです。

C#
Random random = new Random();

int number = random.Next(1, 10);

この場合、出る値は1〜9です。

1以上10未満

10は出ません。

この仕様は、配列やリストのインデックスを扱いやすくするためにも便利です。

C#
string[] names = { "Alice", "Bob", "Charlie" };

int index = random.Next(0, names.Length);
Console.WriteLine(names[index]);

names.Lengthは3ですが、配列のインデックスは0〜2です。random.Next(0, names.Length)なら、0〜2が生成されるため、範囲外アクセスを避けられます。

3-2. minValueは含まれる

Random.Next(minValue, maxValue)では、minValueは含まれます。

C#
int number = random.Next(3, 8);

この場合、出る可能性がある値は次のとおりです。

3, 4, 5, 6, 7

3は出ますが、8は出ません。

つまり、C#のRandom.Nextは次の範囲で値を返します。

minValue <= 乱数 < maxValue

このルールを覚えておけば、ほとんどの範囲指定で迷わなくなります。

3-3. 1〜10を出したい場合はNext(1, 11)と書く

1〜10の整数をランダムに出したい場合は、必ず次のように書きます。

C#
Random random = new Random();

int number = random.Next(1, 11);

Next(1, 10)では、10が出ません。

C#
int wrong = random.Next(1, 10);  // 1〜9
int correct = random.Next(1, 11); // 1〜10

「最大値を含めたいなら、第2引数に最大値 + 1を指定する」と覚えておくとよいでしょう。

3-4. minValueがmaxValueより大きいとエラーになる

Random.Next(minValue, maxValue)では、minValuemaxValueより大きいと例外が発生します。

C#
Random random = new Random();

int number = random.Next(10, 1);

このように書くと、下限が10、上限が1になってしまうため、正しい範囲ではありません。

変数を使う場合は、下限と上限の大小関係に注意しましょう。

C#
int min = 10;
int max = 1;

if (min <= max)
{
int number = random.Next(min, max + 1);
Console.WriteLine(number);
}
else
{
Console.WriteLine("範囲指定が正しくありません。");
}

ユーザー入力を使う場合は、入力値を検証してからNextに渡すのが安全です。

3-5. minValueとmaxValueが同じ場合の挙動

Random.Next(minValue, maxValue)minValuemaxValueが同じ場合、その値が返されます。

C#
Random random = new Random();

int number = random.Next(5, 5);
Console.WriteLine(number);

この場合、結果は常に5です。

乱数というより、固定値を返す動作になります。意図して使う場面は少ないですが、範囲指定を変数で行うときに発生する可能性があります。

C#
int min = 5;
int max = 5;

int number = random.Next(min, max);

この場合は例外にはなりません。ただし、範囲に幅がないため、ランダム性はありません。

4. よく使う乱数範囲指定のサンプルコード

4-1. 0〜9の乱数を生成する

0〜9の整数を生成するには、次のように書きます。

C#
Random random = new Random();

int number = random.Next(10);
Console.WriteLine(number);

または、下限と上限を明示して次のようにも書けます。

C#
int number = random.Next(0, 10);

どちらも0〜9の範囲になります。

0以上10未満

0から始まる範囲では、Next(10)のように引数を1つだけ指定する書き方がよく使われます。

4-2. 1〜100の乱数を生成する

1〜100の整数を生成するには、上限に101を指定します。

C#
Random random = new Random();

int number = random.Next(1, 101);
Console.WriteLine(number);

Random.Next(1, 100)と書くと、1〜99になってしまいます。

C#
int wrong = random.Next(1, 100);   // 1〜99
int correct = random.Next(1, 101); // 1〜100

最大値を含めたい場合は、上限に1を足すのが基本です。

4-3. 配列のインデックスをランダムに選ぶ

配列からランダムに要素を選ぶ場合は、Next(配列.Length)を使います。

C#
Random random = new Random();

string[] fruits = { "Apple", "Banana", "Orange", "Grape" };

int index = random.Next(fruits.Length);
string fruit = fruits[index];

Console.WriteLine(fruit);

fruits.Lengthが4の場合、random.Next(4)は0〜3を返します。配列のインデックスも0〜3なので、ちょうど対応します。

この書き方は、配列の要素数が変わっても安全に使えるため便利です。

4-4. サイコロの目をランダムに生成する

サイコロの目は1〜6なので、次のように書きます。

C#
Random random = new Random();

int dice = random.Next(1, 7);
Console.WriteLine($"サイコロの目: {dice}");

Next(1, 6)では6が出ません。

C#
int wrong = random.Next(1, 6); // 1〜5
int correct = random.Next(1, 7); // 1〜6

ゲームやシミュレーションで乱数を扱う場合、この上限の指定ミスはよくあるので注意しましょう。

4-5. ランダムな要素をリストから取得する

List<T>からランダムに要素を取得する場合も、配列と同じ考え方です。

C#
Random random = new Random();

List<string> items = new List<string>
{
"Sword",
"Shield",
"Potion",
"Ring"
};

int index = random.Next(items.Count);
string selectedItem = items[index];

Console.WriteLine(selectedItem);

items.Countはリストの要素数です。random.Next(items.Count)を使うことで、0〜items.Count - 1のインデックスを取得できます。

ただし、リストが空の場合は注意が必要です。

C#
if (items.Count > 0)
{
int index = random.Next(items.Count);
string selectedItem = items[index];

Console.WriteLine(selectedItem);
}
else
{
Console.WriteLine("リストが空です。");
}

空のリストに対してrandom.Next(0)を使うと0が返されますが、その後にitems[0]へアクセスすると範囲外エラーになります。リストからランダムに取得する場合は、要素が存在するか確認しておきましょう。

5. 小数の乱数を範囲指定する方法

5-1. Random.NextDoubleの基本

整数ではなく小数の乱数を生成したい場合は、Random.NextDoubleを使います。

C#
Random random = new Random();

double value = random.NextDouble();
Console.WriteLine(value);

NextDoubleは、0.0以上1.0未満のdouble型の乱数を返します。

0.0 <= value < 1.0

1.0は含まれません。

5-2. 0.0以上1.0未満の乱数を生成する

NextDoubleをそのまま使うと、0.0以上1.0未満の範囲になります。

C#
Random random = new Random();

for (int i = 0; i < 5; i++)
{
double value = random.NextDouble();
Console.WriteLine(value);
}

実行すると、次のような値が表示されます。

0.238419...
0.872314...
0.049281...
0.663902...
0.415728...

実際の値は実行するたびに変わります。

5-3. 任意の小数範囲に変換する計算式

NextDoubleで任意の小数範囲を作るには、次の計算式を使います。

C#
double value = min + random.NextDouble() * (max - min);

たとえば、minが10.0、maxが20.0の場合は、10.0以上20.0未満の小数が生成されます。

考え方は次のとおりです。

random.NextDouble()        // 0.0以上1.0未満
random.NextDouble() * 10 // 0.0以上10.0未満
10 + random.NextDouble() * 10 // 10.0以上20.0未満

基本形として覚えておくと便利です。

C#
double min = 10.0;
double max = 20.0;

double value = min + random.NextDouble() * (max - min);

5-4. 10.0〜20.0の小数乱数を生成するサンプル

10.0以上20.0未満の小数乱数を生成するサンプルは次のとおりです。

C#
Random random = new Random();

double min = 10.0;
double max = 20.0;

double value = min + random.NextDouble() * (max - min);

Console.WriteLine(value);

複数回生成する場合は、次のようにループできます。

C#
Random random = new Random();

double min = 10.0;
double max = 20.0;

for (int i = 0; i < 5; i++)
{
double value = min + random.NextDouble() * (max - min);
Console.WriteLine(value);
}

このコードでは、10.0以上20.0未満の小数が5回表示されます。

5-5. 小数乱数を整数に丸める場合の注意点

小数の乱数を整数に変換したい場合、Math.RoundMath.FloorMath.Ceiling、キャストなどの方法があります。

C#
double value = 10.0 + random.NextDouble() * 10.0;

int rounded = (int)Math.Round(value);
int floor = (int)Math.Floor(value);
int casted = (int)value;

それぞれの動作は異なります。

C#
Math.Round(value); // 四捨五入
Math.Floor(value); // 小さい整数へ切り下げ
(int)value; // 小数部分を切り捨て

ただし、整数の乱数が欲しいだけなら、基本的にはNextを使う方が適切です。

C#
int number = random.Next(10, 21);

小数を生成してから整数に変換すると、丸め方によって分布に偏りが出る可能性があります。整数が必要な場合はRandom.Next、小数が必要な場合はRandom.NextDoubleを使い分けましょう。

6. Randomを使うときによくある失敗と対策

6-1. ループ内でnew Random()を繰り返さない

C#で乱数を使うときによくある失敗が、ループ内でnew Random()を繰り返すことです。

C#
for (int i = 0; i < 10; i++)
{
Random random = new Random();
int number = random.Next(1, 101);

Console.WriteLine(number);
}

このような書き方は避けた方がよいです。

Randomのインスタンスを短時間に何度も作成すると、環境や実装によっては同じような乱数列が生成される原因になることがあります。基本的には、Randomインスタンスは一度作成して使い回します。

C#
Random random = new Random();

for (int i = 0; i < 10; i++)
{
int number = random.Next(1, 101);
Console.WriteLine(number);
}

このように、ループの外でRandomを作成するのが基本です。

6-2. 同じ乱数が連続して出る原因

同じ乱数が連続して出る原因として、次のようなものがあります。

C#
Random random = new Random();

この処理を短時間で何度も実行すると、同じシード値に近い状態で初期化され、似たような結果になることがあります。

特に、メソッドの中で毎回new Random()している場合は注意が必要です。

C#
int GetRandomNumber()
{
Random random = new Random();
return random.Next(1, 101);
}

このようなメソッドを短時間に連続で呼び出すより、外側で作成したRandomを使い回す方が適切です。

C#
Random random = new Random();

int GetRandomNumber()
{
return random.Next(1, 101);
}

6-3. Randomインスタンスは使い回す

Randomは基本的に使い回しましょう。

C#
Random random = new Random();

int a = random.Next(1, 101);
int b = random.Next(1, 101);
int c = random.Next(1, 101);

Console.WriteLine(a);
Console.WriteLine(b);
Console.WriteLine(c);

メソッドに渡して使うこともできます。

C#
int RollDice(Random random)
{
return random.Next(1, 7);
}

Random random = new Random();

int dice1 = RollDice(random);
int dice2 = RollDice(random);

Console.WriteLine(dice1);
Console.WriteLine(dice2);

このようにすると、不要なインスタンス生成を避けられます。

6-4. staticフィールドでRandomを管理する例

アプリケーション全体でRandomを使い回したい場合は、staticフィールドとして管理する方法があります。

C#
public class RandomService
{
private static readonly Random _random = new Random();

public static int NextInt(int min, int max)
{
return _random.Next(min, max);
}
}

使う側は次のようになります。

C#
int number = RandomService.NextInt(1, 101);
Console.WriteLine(number);

ただし、複数スレッドから同時に使う場合は注意が必要です。近年の.NETでは、後述するRandom.Sharedを使う方法もあります。

6-5. マルチスレッドでRandomを使う場合の注意点

複数のスレッドから同じRandomインスタンスを扱う場合、スレッドセーフ性に注意が必要です。

.NET 6以降では、Random.Sharedを使うと便利です。Random.Sharedは、複数のスレッドから同時に使える共有インスタンスとして提供されています。

C#
int number = Random.Shared.Next(1, 101);
Console.WriteLine(number);

通常のアプリケーションで、簡単に乱数を使いたい場合はRandom.Sharedを利用することで、new Random()の管理を減らせます。

C#
for (int i = 0; i < 10; i++)
{
int number = Random.Shared.Next(1, 101);
Console.WriteLine(number);
}

ただし、セキュリティ用途ではRandom.Sharedではなく、RandomNumberGeneratorを使います。

7. C#のバージョン別に見る乱数生成の選択肢

7-1. 従来のnew Random()を使う方法

従来からよく使われているのは、new Random()でインスタンスを作成する方法です。

C#
Random random = new Random();

int number = random.Next(1, 101);
Console.WriteLine(number);

シンプルでわかりやすく、学習用や小規模な処理では今でもよく使われます。

ただし、同じ処理内で何度もnew Random()を作成するのではなく、1つのインスタンスを使い回すのが基本です。

C#
Random random = new Random();

for (int i = 0; i < 10; i++)
{
Console.WriteLine(random.Next(1, 101));
}

7-2. Random.Sharedを使う方法

.NET 6以降では、Random.Sharedを使うことができます。

C#
int number = Random.Shared.Next(1, 101);
Console.WriteLine(number);

Random.Sharedを使うと、自分でRandomインスタンスを作らずに、共有のRandomインスタンスを利用できます。

配列からランダムに要素を選ぶ場合も簡潔に書けます。

C#
string[] names = { "Alice", "Bob", "Charlie" };

string name = names[Random.Shared.Next(names.Length)];
Console.WriteLine(name);

7-3. .NET 6以降でRandom.Sharedが便利な理由

Random.Sharedが便利な理由は、次のような点にあります。

・new Random()の管理が不要
・短時間に複数インスタンスを作る問題を避けやすい
・複数スレッドから利用しやすい
・コードが短くなる

たとえば、ちょっとした乱数を生成したいだけなら、次のように書けます。

C#
int dice = Random.Shared.Next(1, 7);
Console.WriteLine(dice);

従来のように毎回次のようなコードを書く必要がありません。

C#
Random random = new Random();
int dice = random.Next(1, 7);

ただし、古い.NET環境ではRandom.Sharedが使えない場合があります。その場合は、従来どおりnew Random()を使います。

7-4. セキュリティ用途ではRandomを使わない

Randomは、ゲーム、表示のランダム化、簡単な抽選、テストデータなどには便利です。

しかし、次のようなセキュリティ用途には使わないでください。

・パスワード生成
・認証トークン生成
・セッションID生成
・暗号鍵生成
・ワンタイムコード生成

Randomは暗号学的に安全な乱数ではありません。予測されて困る値には使わないのが原則です。

セキュリティ上重要な値には、System.Security.Cryptography.RandomNumberGeneratorを使います。

7-5. 暗号学的乱数が必要な場合はRandomNumberGeneratorを使う

暗号学的に強い乱数が必要な場合は、RandomNumberGeneratorを使います。

整数の範囲指定をしたい場合は、RandomNumberGenerator.GetInt32が便利です。

C#
using System.Security.Cryptography;

int number = RandomNumberGenerator.GetInt32(1, 101);
Console.WriteLine(number);

このコードでは、1以上101未満、つまり1〜100の整数が生成されます。

RandomNumberGenerator.GetInt32も、上限は含まれません。

C#
int code = RandomNumberGenerator.GetInt32(100000, 1000000);
Console.WriteLine(code);

この例では、100000〜999999の6桁の数値を生成できます。

8. Random.Next以外で範囲指定の乱数を作る方法

8-1. RandomNumberGenerator.GetInt32を使う

Random.Next以外で範囲指定の整数乱数を作る方法として、RandomNumberGenerator.GetInt32があります。

C#
using System.Security.Cryptography;

int number = RandomNumberGenerator.GetInt32(10);
Console.WriteLine(number);

この場合、0以上10未満の整数が生成されます。

下限と上限を指定する場合は、次のように書きます。

C#
int number = RandomNumberGenerator.GetInt32(1, 101);
Console.WriteLine(number);

これは1〜100の範囲です。

Random.Nextと同じように、下限は含まれ、上限は含まれません。

8-2. セキュアな整数乱数を範囲指定する

セキュアな整数乱数を範囲指定する場合は、次のようにします。

C#
using System.Security.Cryptography;

int min = 1;
int max = 100;

int number = RandomNumberGenerator.GetInt32(min, max + 1);

Console.WriteLine(number);

このコードでは、1〜100の整数を暗号学的に強い乱数として生成できます。

パスワードや認証コードのように、予測されると困る値にはRandomではなくRandomNumberGeneratorを使いましょう。

たとえば、6桁の認証コードを生成する場合は次のように書けます。

C#
using System.Security.Cryptography;

int code = RandomNumberGenerator.GetInt32(100000, 1000000);

Console.WriteLine(code);

8-3. ゲーム・抽選・パスワード生成で使い分ける

乱数生成では、用途に応じた使い分けが重要です。

ゲーム内のサイコロや敵の出現、ランダムな演出にはRandomRandom.Sharedで十分なことが多いです。

C#
int dice = Random.Shared.Next(1, 7);

一方、パスワード生成や認証コード、トークン生成にはRandomNumberGeneratorを使います。

C#
using System.Security.Cryptography;

int code = RandomNumberGenerator.GetInt32(100000, 1000000);

簡単にまとめると、次のようになります。

ゲーム・表示・テスト用      → Random / Random.Shared
セキュリティ用途 → RandomNumberGenerator

8-4. RandomとRandomNumberGeneratorの違い

RandomRandomNumberGeneratorの大きな違いは、乱数の目的です。

Randomは、一般的な擬似乱数を生成するためのクラスです。ゲームやシミュレーション、テストデータ作成などに向いています。

C#
int number = Random.Shared.Next(1, 101);

一方、RandomNumberGeneratorは、暗号学的に強い乱数を生成するためのクラスです。予測されると困る値に使います。

C#
using System.Security.Cryptography;

int number = RandomNumberGenerator.GetInt32(1, 101);

Randomは扱いやすく高速ですが、セキュリティ用途には向きません。RandomNumberGeneratorはセキュリティ用途に適していますが、単なるゲーム演出などでは過剰な場合もあります。

8-5. 用途別のおすすめ実装

通常のC#アプリケーションで範囲指定の乱数を使うなら、次のように使い分けるのがおすすめです。

簡単な乱数生成なら、Random.Sharedを使います。

C#
int number = Random.Shared.Next(1, 101);

古い.NET環境や、明示的にインスタンスを管理したい場合は、new Random()を使います。

C#
Random random = new Random();

int number = random.Next(1, 101);

セキュリティ用途では、RandomNumberGenerator.GetInt32を使います。

C#
using System.Security.Cryptography;

int number = RandomNumberGenerator.GetInt32(1, 101);

用途ごとの目安は次のとおりです。

学習用・簡単なサンプル       → new Random()
.NET 6以降の通常用途 → Random.Shared
認証・暗号・パスワード用途 → RandomNumberGenerator

9. C#の乱数範囲指定に関するよくある質問

9-1. Random.Next(1, 10)で10は出るのか

Random.Next(1, 10)で10は出ません。

この場合、生成される値は1以上10未満です。

C#
Random random = new Random();

int number = random.Next(1, 10);

出る可能性がある値は次のとおりです。

1, 2, 3, 4, 5, 6, 7, 8, 9

10を出したい場合は、次のように書きます。

C#
int number = random.Next(1, 11);

9-2. 0からではなく1から乱数を作るにはどうするか

0からではなく1から乱数を作るには、Next(minValue, maxValue)を使います。

C#
Random random = new Random();

int number = random.Next(1, 101);
Console.WriteLine(number);

このコードでは、1〜100の整数が生成されます。

1〜10なら次のように書きます。

C#
int number = random.Next(1, 11);

1〜6なら次のように書きます。

C#
int dice = random.Next(1, 7);

最大値を含めたい場合は、第2引数に最大値 + 1を指定します。

9-3. 同じ乱数を再現するにはどうするか

同じ乱数列を再現したい場合は、Randomのコンストラクターに同じシード値を指定します。

C#
Random random = new Random(123);

for (int i = 0; i < 5; i++)
{
Console.WriteLine(random.Next(1, 101));
}

同じシード値を使うと、同じ環境・同じ実装条件では同じ順序の乱数列を得られます。

テストやデバッグでは、乱数の再現性があると便利です。

C#
Random random1 = new Random(123);
Random random2 = new Random(123);

Console.WriteLine(random1.Next(1, 101));
Console.WriteLine(random2.Next(1, 101));

このように、同じシードを指定すると、同じ順番で値が生成されます。

ただし、セキュリティ用途では、固定シードによる再現可能な乱数は使うべきではありません。

9-4. 乱数の重複を避けるにはどうするか

乱数の重複を避けたい場合は、生成済みの値を管理する必要があります。

たとえば、1〜10の数字を重複なしで取得したい場合は、リストをシャッフルする方法が便利です。

C#
List<int> numbers = Enumerable.Range(1, 10).ToList();

for (int i = numbers.Count - 1; i > 0; i--)
{
int j = Random.Shared.Next(i + 1);

int temp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = temp;
}

foreach (int number in numbers)
{
Console.WriteLine(number);
}

この方法では、1〜10の数値を重複なしでランダムな順番に並べ替えられます。

単純にRandom.Next(1, 11)を繰り返すだけでは、同じ値が何度も出る可能性があります。

C#
for (int i = 0; i < 10; i++)
{
Console.WriteLine(Random.Shared.Next(1, 11));
}

重複を許さない場合は、生成済みの値をHashSet<int>で管理する方法もあります。

C#
HashSet<int> set = new HashSet<int>();

while (set.Count < 5)
{
int number = Random.Shared.Next(1, 11);
set.Add(number);
}

foreach (int number in set)
{
Console.WriteLine(number);
}

このコードでは、1〜10の中から重複なしで5個の数値を取得できます。

9-5. 範囲内でランダムな小数を作るにはどうするか

範囲内でランダムな小数を作るには、Random.NextDoubleを使います。

基本の計算式は次のとおりです。

C#
double value = min + random.NextDouble() * (max - min);

たとえば、5.0以上15.0未満の小数を作る場合は次のように書きます。

C#
Random random = new Random();

double min = 5.0;
double max = 15.0;

double value = min + random.NextDouble() * (max - min);

Console.WriteLine(value);

NextDoubleは0.0以上1.0未満の値を返すため、上記の式で任意の範囲に変換できます。

整数ならNext、小数ならNextDoubleを使うと覚えておきましょう。

まとめ

C#で乱数の範囲指定をするには、主にRandom.Nextを使います。

整数の乱数を作る基本は次のとおりです。

C#
Random random = new Random();

int number = random.Next(minValue, maxValue);

Random.Next(minValue, maxValue)では、minValueは含まれ、maxValueは含まれません。

minValue <= 乱数 < maxValue

そのため、1〜10の乱数を作りたい場合は、次のように書きます。

C#
int number = random.Next(1, 11);

0〜9なら次のように書けます。

C#
int number = random.Next(10);

配列やリストからランダムに要素を取得する場合は、LengthCountを上限に指定します。

C#
string[] items = { "A", "B", "C" };

string item = items[Random.Shared.Next(items.Length)];

小数の乱数が必要な場合は、NextDoubleを使います。

C#
double value = min + random.NextDouble() * (max - min);

.NET 6以降では、簡単な乱数生成にRandom.Sharedを使うと便利です。

C#
int number = Random.Shared.Next(1, 101);

一方、パスワード、認証コード、トークンなど、セキュリティに関わる用途ではRandomを使わず、RandomNumberGeneratorを使います。

C#
using System.Security.Cryptography;

int number = RandomNumberGenerator.GetInt32(1, 101);

C#の乱数範囲指定では、「下限は含む、上限は含まない」というルールを理解することが最も重要です。このルールを押さえておけば、Random.Nextを使った整数乱数、配列インデックスのランダム選択、サイコロ、抽選、小数乱数まで、正しく実装できるようになります。