web-dev-qa-db-ja.com

uniform_int_distributionの範囲を変更します

だから私はランダムオブジェクトを持っています:

typedef unsigned int uint32;

class Random {
public:
    Random() = default;
    Random(std::mt19937::result_type seed) : eng(seed) {}

private:
    uint32 DrawNumber();
    std::mt19937 eng{std::random_device{}()};
    std::uniform_int_distribution<uint32> uniform_dist{0, UINT32_MAX};
};

uint32 Random::DrawNumber()
{
    return uniform_dist(eng);
}

分布の上限を(別の関数またはその他の方法で)変更できる最善の方法は何ですか?

(他のスタイルの問題についても喜んでアドバイスを受けます)

24
LordAro

配布オブジェクトは軽量です。乱数が必要な場合は、新しい分布を作成するだけです。私はこのアプローチをゲームエンジンで使用しており、ベンチマーク後は、古き良きRand()を使用するのと同等です。

また、GoingNative 2013ライブストリームで配信の範囲を変更する方法を尋ねたところ、標準委員会のメンバーであるStephen T. Lavavejは、パフォーマンスの問題ではないため、単に新しい配信を作成することを提案しました。

これが私があなたのコードを書く方法です:

using uint32 = unsigned int;

class Random {
public:
    Random() = default;
    Random(std::mt19937::result_type seed) : eng(seed) {}
    uint32 DrawNumber(uint32 min, uint32 max);

private:        
    std::mt19937 eng{std::random_device{}()};
};

uint32 Random::DrawNumber(uint32 min, uint32 max)
{
    return std::uniform_int_distribution<uint32>{min, max}(eng);
}
43
Vittorio Romeo

param() メソッドを使用して、_std::uniform_int_distribution<uint32>::param_type_を作成し、範囲を変更するだけです。テンプレートのノイズはdecltypeで削減できます。

_decltype(uniform_dist.param()) new_range (0, upper);
uniform_dist.param(new_range);
_
8
Brett Hale

私の例では、DrawNumber関数をpublicにしています。上限を取るオーバーロードを提供して、新しい_uniform_int_distribution::param_type_を uniform_int_distribution::operator() に渡すことができます

_param_type_は、対応する分布と同じ引数を使用して構築できます。

N3337以降、§26.5.1.6/ 9[Rand.req.dist]

分布のパラメーターに対応する引数を取るDのコンストラクターごとに、Pは、同じ要件に従い、数、タイプ、およびデフォルト値が同じ引数を取る対応するコンストラクターを持つ必要があります。さらに、分布のパラメーターに対応する値を返すDのメンバー関数のそれぞれについて、Pは、同じ名前、タイプ、およびセマンティクスを持つ対応するメンバー関数を持つ必要があります。

ここで、Dは乱数分布関数オブジェクトのタイプであり、PDの関連する_param_type_によって名前が付けられたタイプです。

_#include <iostream>
#include <random>

typedef unsigned int uint32;

class Random {
public:
    Random() = default;
    Random(std::mt19937::result_type seed) : eng(seed) {}

    uint32 DrawNumber();
    uint32 DrawNumber(uint32 ub);

private:
    std::mt19937 eng{std::random_device{}()};
    std::uniform_int_distribution<uint32> uniform_dist{0, UINT32_MAX};
};

uint32 Random::DrawNumber()
{
    return uniform_dist(eng);
}

uint32 Random::DrawNumber(uint32 ub)
{
    return uniform_dist(eng, decltype(uniform_dist)::param_type(0, ub));
}

int main()
{
  Random r;
  std::cout << r.DrawNumber() << std::endl;
  std::cout << r.DrawNumber(42) << std::endl;
}
_
6
Praetorian