1

合同乱数ジェネレーター クラスの適切なクラス階層を作成しようとしています (つまり、3 つの整数パラメーター - Mabがあることを意味します)。基本クラスは派生クラスのインターフェイスを提供する必要があり (したがって、抽象化する必要があります)、派生クラスではMabstatic constにする必要があると判断しました (これらは派生クラス全体で同じであるため)。

generate()関数はすべての合同乱数ジェネレーターで同じであるため、その定義は基本クラス内に配置する必要があります。問題は、この関数がMabのすべてを使用することですが、これらを基本クラスでstatic constにすることはできません。

問題を説明するために、考えられる解決策の 1 つを示します。ただし、派生クラスのインスタンスごとに余分なlong long変数を 3 つ作成するので、これでは満足できないので、もっとエレガントなデザインを提案できないか考えています。

class RandomGenerator{
   protected:
       unsigned int seed;

       const long long int M;
       const long long int a;
       const long long int b;

   public:
       RandomGenerator(unsigned int, long long, long long, long long);

       virtual long double generate()  const = 0;
};

long double RandomGenerator::generate() const{
   static long long prv = seed;

   return (long double) (prv = (a * prv + b) % M) / (M-1);
} 

class RandU : public RandomGenerator {
    private:
       static const long long M = 2147483648LL;
       static const long long a = 65539;
       static const long long b = 0;

   public:
       RandU(unsigned int);

       virtual long double generate() const;
 };


RandU::RandU(unsigned int nseed): RandomGenerator(nseed, M, a, b){}

long double RandU::generate() const{
    return RandomGenerator::generate();
 }
4

2 に答える 2

1

これを解決する 1 つの方法は、階層にクラスを追加することです。

class RandomGenerator {
protected:
  unsigned int seed;

public:
  RandomGenerator(unsigned int, long long, long long, long long);

  virtual long long getM() = 0;
  virtual long long geta() = 0;
  virtual long long getb() = 0;

  virtual long double generate() const;
};


inline long double RandomGenerator::generate() const {
  static long long prv = seed;
  return (long double) (prv = (a * prv + b) % M) / (M-1);
} 

class GeneralRandomGenerator : public RandomGenerator
{
  const long long int M;
  const long long int a;
  const long long int b;
public:
  virtual long long getM() { return M; }
  virtual long long geta() { return a; }
  virtual long long getb() { return b; }
};


class RandU : public RandomGenerator {
private:
  static const long long M = 2147483648LL;
  static const long long a = 65539;
  static const long long b = 0;

public:
  RandU(unsigned int);

  virtual long long getM() { return RandU::M; }
  virtual long long geta() { return RandU::a; }
  virtual long long getb() { return RandU::b; }

  virtual long double generate() const;
};


RandU::RandU(unsigned int nseed): RandomGenerator(nseed, M, a, b){}

inline long double RandU::generate() const {
  return RandomGenerator::generate();
}

ご覧のとおり、私は から派生GeneralRandomGeneratorしましたRandomGeneratorM前者には、aおよびのメンバーが含まれるようになりましbたが、後者には純粋な仮想アクセス関数getM()geta()およびが含まれていgetb()ます。これらのGeneralRandomGeneratorアクセス関数では、メンバーを返すために実装されています。

しかし、RandU依然として最上位レベルから派生している では、静的メンバーの値を返すようにアクセサーが定義されています。

このようにしてgenerate()、最高レベルの関数はアクセサー関数を介して必要なものにアクセスできますが、値は実際には静的メンバーまたは非静的メンバーから取得されるか、まったく異なる場所から取得される可能性があります。利点は明らかに、のためRandUのスペースを必要としないことと、それらのメンバーがその中に存在しないことです。Mab

ただし、欠点は、 etc へのアクセスであっても、仮想GeneralRandomGenerator関数Mを呼び出すことによって実行されることです。これは、静的メンバーへのアクセスを直接コーディングする場合よりもパフォーマンスが低下することを意味します。

それを回避する1つの方法は、一般化された for をgenerate()クラス外の別の関数として提供し、 passをM引数として提供することです:ab

namespace general
{
  inline long double generate(long long a, long long b, long long M) const {
    static long double prv = seed;
    return (prv = (a * prv + b) % M) / (M-1);
  }
}

class GeneralRandomGenerator
{
protected:
  unsigned int seed;

public:
  long long a;
  long long b;
  long long M;

  virtual long double generate() const {
    return general::generate(a,b,M);
  }
};

class RandomU
{
private:
  static long long a;
  static long long b;
  static long long M;
public:
  virtual long double generate() const {
    return general::generate(a,b,M);
  }
};
于 2012-10-21T09:32:21.690 に答える
1

実際、あなたの構成は問題ありませんRandU。クラスのサイズは増加しません。sizeof関数を使用して、これが真であることを確認できます。

int main() {
    cout << sizeof(RandomGenerator) << endl;
    cout << sizeof(RandU) << endl;
    return 0;
}

これは戻ります

32
32

ここで完全なコードを見ることができます: http://ideone.com/HNqeOC

于 2012-10-21T08:48:46.650 に答える