メインコンテンツまでスキップ

チュートリアルランダム・クラス

📚 Source Page

このチュートリアルではRandomクラスである。Random数字は、ゲーム、暗号、オーディオなど、あらゆる場面で役に立つ。

レベル初心者

プラットフォーム:Windows, macOS, Linux, iOS, Android

クラス: Random,Range,BigInteger,Colour

スタート

このチュートリアルのデモ・プロジェクトのダウンロードはこちらから:PIP|ZIP.プロジェクトを解凍し、最初のヘッダーファイルをProjucerで開く。

このステップでヘルプが必要な場合は、以下を参照してください。Tutorial: Projucer Part 1: Getting started with the Projucer.

デモ・プロジェクト

デモ・プロジェクトでは、シンプルなテキスト・コンソールをセットアップし、さまざまな操作の結果を表示できるようにしています。これによってRandomクラスがあります。

デフォルトの設定では、デモ・プロジェクトはランダムに生成された100個の32ビット整数を表示する。これらの値は、次の範囲にほぼ一様に分布していなければならない。-2,147,483,648 ..2,147,483,647.もちろん、これらの値は本当にランダムなものではない。コンピュータによって生成されたものなので、これらはきんじランダム.ほとんどの目的にはRandomオブジェクトは十分にランダムであるが、特定の重要なアプリケーションや専門的なアプリケーションでは、より洗練されたテクニックを使用する必要があるかもしれない。

テストベッド・コード

このチュートリアルでは、デモ・プロジェクトの一部を変更し、以下の機能のさまざまなデモンストレーションを行います。Randomクラスである。これから説明するコードはすべてMainComponentクラスである。実際、最初のインスタンスでの変更の多くはrunExample()関数である。

    void runExample()
{
logMessage ("------------------------- START --------------------------");

for (auto iteration = 0; iteration < 100; ++iteration)
{
auto randomInt = juce::Random::getSystemRandom().nextInt();

logMessage (juce::String (randomInt));
}

logMessage ("----------------------- FINISHED -------------------------");
}

ここでは、共有の(グローバルな)Randomオブジェクトを使用する。Random::getSystemRandom()関数を使用します。私たちはRandom::nextInt()このシステムで機能するRandomオブジェクトを使用して乱数を生成します。ほとんどの場合、このシステム・ランダム・オブジェクトを使ってすべての乱数を生成すれば十分です。しかし、場合によってはRandomクラスで生成されます。これは通常、生成している値が別のスレッドで生成されている場合である。Tutorial: Build a white noise generator.2つ以上のスレッドがシステムにアクセスしようとした場合Randomオブジェクトを使用すると、シーケンスが破損し、問題が発生する可能性がある。

制限範囲

によって生成される値の範囲を制限したいと思うのは、ほぼ間違いないだろう。Randomクラスである。これは単純な算数でできるがRandomクラスはさらに簡単だ。

最大値の設定

最大値を設定するにはRandom::nextInt()のように整数を指定する:

auto randomInt = juce::Random::getSystemRandom().nextInt (6);

これは最大値を、渡された引数より1小さい値に設定する。この場合、値は以下の範囲になる。0 ..5.この場合、引数は可能な結果の数であると考えた方が簡単かもしれない。最大値として6を使うということは、可能な結果が6つあるということである。これは、ダイスの面が数字であることを除けば、ダイスを振るのと同じである。0 ..5よりも1 ..6!

最小値と最大値の設定

もちろん1 ..6このように1を追加すればいい:

auto randomInt = juce::Random::getSystemRandom().nextInt (6) + 1;

しかしRandomクラスを渡すことで、この処理を行うことができます。Rangeオブジェクト

auto randomInt = juce::Random::getSystemRandom().nextInt (juce::Range (1, 7));

最大値はやはりRandomオブジェクトを生成できるようにする。最小値は包括的そして最大値は排他的.

その他の数値タイプ

上記の例では、生成される値はすべて32ビット整数の範囲である。またRandomクラスは64ビットの整数値や、任意の大きさの整数を生成することができます。BigIntegerクラスである。

より大きな整数

64ビット整数を生成するにはRandom::nextInt64()関数である:

auto randomInt = juce::Random::getSystemRandom().nextInt64();

の範囲の整数を生成する。-9,223,372,036,854,775,808 ..9,223,372,036,854,775,807.64ビット整数でより小さい範囲を指定するには、自分で演算を行う必要がある。

任意に大きな整数を生成するにはRandom::nextLargeNumber()関数を使用します。これはBigIntegerオブジェクトを受け取りBigIntegerオブジェクトを引数にとり、最大値を示す(ここでも最大値は排他的):

void runExample()
{
logMessage ("------------------------- START --------------------------");

juce::BigInteger maximumValue;
maximumValue.setBit (256);

for (auto iteration = 0; iteration < 100; ++iteration)
{
auto randomInt = juce::Random::getSystemRandom().nextLargeNumber (maximumValue);
logMessage (randomInt.toString (10));
}

logMessage ("----------------------- FINISHED -------------------------");
}

の最大値を非常に大きくする。2256のビット256を設定する。maximumValue BigIntegerオブジェクトを返します。出力はランダムに生成された非常に大きな整数である。例えば

...
104920467355765962354471349450287456411052143302125448224736731840703932891139
113537286625531390989138082815985050172086775818737779507269901485377454431686
57847088262227027688174446009482649397747696846679750345153185249067937632876
54822036781617285561665007930420018266697875685845320423632890189355412858007
69785221527278648790869522951189615281519473001003509768672723497611119666776
53474255551114041705196319572561227500136240211575200675493708156631961926592
99704173402721617789464355135995656339243151513499563088758939994549638940776
89393625021259981953975863158742834192382645809510667002452217673394247775970
16555501734946882319812302845214545517919239951054372751749796998179564377182
----------------------- FINISHED -------------------------

浮動小数点値

についてRandomクラスは浮動小数点値も生成できる:

void runExample()
{
logMessage ("------------------------- START --------------------------");

for (auto iteration = 0; iteration < 100; ++iteration)
{
auto randomValue = juce::Random::getSystemRandom().nextFloat();

logMessage (juce::String (randomValue));
}

logMessage ("----------------------- FINISHED -------------------------");
}

そして、それを生み出すことができる。double価値観の違いだ:

auto randomValue = juce::Random::getSystemRandom().nextDouble();

いずれの場合も、返される値は以下の範囲にある。0.0 .. 1.0.別の範囲を生成するには、自分で演算を適用する必要があります (Tutorial: Build a white noise generatorを使うことができる。)を使うことができる。jmap()関数を使用する。

価値の可視化

生成された乱数値を視覚化することは、数値の長いリストを見るよりも便利です。これは、一様分布以外の分布を持つ乱数値のセットが必要な場合に特に便利です。これはまた、いくつかの興味深いパターンを作成することができます。

ランダムな長方形の位置

を変更する。MainContentComponentを次の単純なコードに置き換える:

class MainContentComponent   : public juce::Component
{
public:
MainContentComponent()
{
setSize (600, 600);
}

~MainContentComponent() {}

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::black);
g.setColour (juce::Colours::orange);

auto& random = juce::Random::getSystemRandom();
juce::Rectangle rect (0, 0, 20, 20);

for (auto i = 0; i < 100; ++i)
{
rect.setCentre (random.nextInt (getWidth()), random.nextInt (getHeight()));
g.drawRect (rect);
}
}

private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...Definition juce_PlatformDefs.h:262

このような画像が生成されるはずだ:

ランダムに生成された100個の長方形
ランダムに生成された100個の長方形

ウィンドウのサイズを変更してみてください。ウィンドウのサイズが変更されるたびに、新しい矩形のセットが生成されることに気づくだろう。paint()関数が呼び出される。

エクササイズ

矩形の数や大きさを変えてみてください。例えば、矩形の大きさをウィンドウの大きさに比例させることもできます。矩形の代わりに円を描いてみる。

ランダムな長方形のサイズ

長方形の大きさをランダムにするためには、こうすればいい:

void paint (Graphics& g) override
{
g.fillAll (juce::Colours::black);
g.setColour (juce::Colours::orange);

auto& random = juce::Random::getSystemRandom();
juce::Rectangle rect (0, 0, 20, 20);

for (auto i = 0; i < 100; ++i)
{
rect.setSize (random.nextInt (getWidth() / 4), random.nextInt (getHeight() / 4));
rect.setCentre (random.nextInt (getWidth()), random.nextInt (getHeight()));
g.drawRect (rect);
}
}
GraphicsA graphics context, used for drawing a component or image.Definition juce_GraphicsContext.h:57
Graphics::drawRectvoid drawRect(int x, int y, int width, int height, int lineThickness=1) constDraws a rectangular outline, using the current colour or brush.
Graphics::fillAllvoid fillAll() constFills the context's entire clip region with the current colour or brush.
Graphics::setColourvoid setColour(Colour newColour)Changes the current drawing colour.

毎回正方形を生成させるには、こうすればいい:

for (auto i = 0; i < 100; ++i)
{
auto size = random.nextInt (jmin (getWidth(), getHeight()) / 4);
rect.setSize (size, size);
rect.setCentre (random.nextInt (getWidth()), random.nextInt (getHeight()));
g.drawRect (rect);
}
jminconstexpr Type jmin(Type a, Type b)Returns the smaller of two values.Definition juce_MathsFunctions.h:367

ランダムカラー

Coloursもランダム化できるが、ランダム化を使って相性の良い色を作るのは少し難しい。例えば、これはそれぞれの長方形に新しいランダムな色を生成します。しかしこの色はいずれも色だ:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::black);

auto& random = juce::Random::getSystemRandom();
juce::Rectangle rect (0, 0, 20, 20);

for (auto i = 0; i < 100; ++i)
{
juce::Colour colour (random.nextInt (256),
random.nextInt (256),
random.nextInt (256));

g.setColour (colour);

rect.setCentre (random.nextInt (getWidth()), random.nextInt (getHeight()));
g.drawRect (rect);
}
}

このようになるはずだ:

ランダムに生成された色
ランダムに生成された色

単純な方法で色を限定するには、要素の1つか2つ(赤、緑、青)だけをランダムにして、値の範囲を限定すればいい:

juce::Colour colour (random.nextInt (juce::Range (100, 256)),
random.nextInt (juce::Range (50, 200)),
200);

g.setColour (colour);

これにより、ピンクや紫の色合いが生まれる:

ピンクとパープル
ピンクとパープル

具体的には、色相、彩度、明度を用いて色を生成することができる。例えば、オレンジは色相が約30°(または0.0 .. 1の範囲)。ランダムな色相を0.05 .. 0.15これらはすべて異なるオレンジの色合いであるべきだ。

for (auto i = 0; i < 100; ++i)
{
auto hue = juce::jmap (random.nextFloat(), 0.05f, 0.15f);
g.setColour (juce::Colour::fromHSV (hue, 0.9f, 0.9f, 1.0f));

rect.setCentre (random.nextInt (getWidth()), random.nextInt (getHeight()));
g.drawRect (rect);
}
ランダムに生成されるオレンジの色合い
ランダムに生成されるオレンジの色合い
エクササイズ

相性の良い色をランダムに集めてみよう。

配列からランダムに選択する

配列を使って、特定の色のセットからランダムに選ぶこともできる:

class MainContentComponent   : public Component
{
public:
MainContentComponent()
{
colours.add (juce::Colours::white);
colours.add (juce::Colours::orange);
colours.add (juce::Colours::lightgreen);

setSize (400, 400);
}

~MainContentComponent() {}

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::black);

auto& random = Random::getSystemRandom();
juce::Rectangle rect (0.0f, 0.0f, 5.0f, 5.0f);

for (auto i = 0; i < 1000; ++i)
{
g.setColour (colours[random.nextInt (colours.size())]);
rect.setCentre ((float) random.nextInt (getWidth()),
(float) random.nextInt (getHeight()));
g.drawEllipse (rect, 1.0f);
}
}

private:
juce::Array colours;

//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};
ComponentThe base class for all JUCE user-interface objects.Definition juce_Component.h:48
Random::getSystemRandomstatic Random & getSystemRandom() noexceptThe overhead of creating a new Random object is fairly small, but if you want to avoid it,...

ここでは、項目を配列に格納している。ランダムに項目を選択するために、配列のサイズに基づいてランダムな値を生成します。そして、この値を配列のインデックスとして使用します。

その他の分配金

このチュートリアルで生成された乱数はすべて、最小値と最大値の間に一様に分布しています。これは統計学のチュートリアルではありませんが、ランダムに生成された特定の値を他の値よりも発生しやすくする簡単な方法をいくつか知っておくと便利です。これは、ゲーム、CGアート、ジェネレイティブサウンドや音楽に応用できます。

以下のコードでは、ウィンドウ全体に一様に分布した1,000個の円を生成している:

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::black);
g.setColour (juce::Colours::orange);

auto& random = juce::Random::getSystemRandom();
juce::Rectangle rect (0.0f, 0.0f, 5.0f, 5.0f);

for (auto i = 0; i < 1000; ++i)
{
rect.setCentre ((float) random.nextInt (getWidth()),
(float) random.nextInt (getHeight()));
g.drawEllipse (rect, 1.0f);
}
}
一様分布円
一様分布円

画像から、円がほぼ均一に分布していることがわかるだろう。

線形分布とは、範囲の一端にある値が他の値よりも可能性が高いというものです。範囲全体の値は、範囲のもう一方の端に向かって可能性が低くなります。この2点間の確率は線形に変化します。これを実装する簡単な方法は、別の乱数値の結果に基づいて1つの乱数値を生成することです。以下の例ではxそしてy円の座標。

for (auto i = 0; i < 1000; ++i)
{
auto x = random.nextInt (random.nextInt (Range (1, getWidth())));
auto y = random.nextInt (random.nextInt (Range (1, getHeight())));

rect.setCentre (x, y);
g.drawEllipse (rect, 1.0f);
}
RangeA general-purpose range object, that simply represents any linear range with a start and end point.Definition juce_Range.h:55
xfloat xDefinition juce_UnityPluginInterface.h:200
yfloat float yDefinition juce_UnityPluginInterface.h:200

ここでは、ランダムな値を1つ生成し、その結果をRandom::nextInt()関数を使って最終値を生成する。

注記

に渡される最大値としてゼロを使うことはできない。Random::nextInt()関数を使うので、最初の乱数が最小値1であることを確認する必要がある。

結果はこのようになるはずだ:

左上を中心としたサークル
左上を中心としたサークル

ゼロに向かう値の方が可能性が高いので、円は左上隅に集中しているように見える。円を中心に表示するには、コードを次のように変更する:

auto centreX = getWidth()  / 2;
auto centreY = getHeight() / 2;

for (auto i = 0; i < 1000; ++i)
{
auto x0 = random.nextInt (juce::Range (1, getWidth() / 2));
auto x = random.nextInt (juce::Range (centreX - x0, centreX + x0));
auto y0 = random.nextInt (juce::Range (1, getHeight() / 2));
auto y = random.nextInt (juce::Range (centreY - y0, centreY + y0));

rect.setCentre (x, y);
g.drawEllipse (rect, 1.0f);
}

加重分布

場合によっては、特定の結果の確率に特別な重み付けをしたいこともあるだろう。先ほどの例で、配列の3色からランダムに選んだ場合を考えてみよう。白が最も可能性が高く、オレンジは可能性が低く、緑はオレンジよりもさらに可能性が低いとします。確率は次の表のように定義できる:

カラー確率
ホワイト70%
オレンジ25%
グリーン5%

の配列を追加することもできる。ウェイトを、重みのインデックスが色のインデックスに対応するコードに置き換えた:

class MainContentComponent   : public juce::Component
{
public:
MainContentComponent()
{
colours.add (juce::Colours::white);
weights.add (0.7f);

colours.add (juce::Colours::orange);
weights.add (0.25f);

colours.add (juce::Colours::lightgreen);
weights.add (0.05f);

setSize (400, 400);
}

void paint (juce::Graphics& g) override
{
g.fillAll (juce::Colours::black);

juce::Random random;
juce::Rectangle rect (0.0f, 0.0f, 5.0f, 5.0f);

auto sumOfWeights = sumFloatArray (weights); // [1]

for (auto i = 0; i < 1000; ++i)
{
g.setColour (colourAtQuantile (random.nextFloat() * sumOfWeights)); // [2]

rect.setCentre ((float) random.nextInt (getWidth()),
(float) random.nextInt (getHeight()));

g.drawEllipse (rect, 1.0f);
}
}

private:
static float sumFloatArray (const juce::Array& values)
{
auto sum = 0.0f;

for (auto value : values)
sum += value;

return sum;
}

static int indexOfQuantile (const juce::Array& weights, float quantile)
{
auto runningTotal = 0.0f; // [4]

for (auto weight : weights)
{
runningTotal += weight;

if (quantile < runningTotal) // [5]
return weights.indexOf (weight);
}

return -1;
}

juce::Colour colourAtQuantile (float quantile) const // [3]
{
auto index = indexOfQuantile (weights, quantile);
return index < 0 ? juce::Colours::transparentBlack : colours[index];
}

//==============================================================================
juce::Array colours;
juce::Array weights;

//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
};

これは次のように機能する:

  • [1]乱数を生成するには、まず重みの和を取る。この場合、重みの和は1.0であることが分かっているが、この手法では重みは1.0にはならない。必要を合計して1.0とする。
  • [2]の範囲で乱数を生成する。0 ... 合計.
  • [3]:そのcolourAtQuantile()関数はこの値を使って色を見つける。
  • [4]これは、重みの配列を繰り返しながら、重みの合計を計算し続けることで達成される。
  • [5]実行中の合計がランダムに生成された値を超えたら、その色を見つけたことになる。
注記

この最後の例のコードはRandomTutorial_02.hファイルにある。

結果は以下のスクリーンショットの通り:

重み付けされた色の選択
重み付けされた色の選択

概要

このチュートリアルではRandomクラスと一般的な乱数生成について説明します。このチュートリアルを読めば、次のことができるようになるでしょう:

  • ランダムな整数と浮動小数点値を生成する。
  • 生成される乱数の範囲を制限する。
  • ランダムな値を使用して描画タスクを実行します。
  • ランダムに生成された色の特定の範囲を生成する。
  • 配列から値をランダムに選択する。

参照