随机但可预测的数字生成器? [C ++]

时间:2012-02-13 23:10:52

标签: c++ random formula weather forecasting

好吧,我真的不知道如何搜索我正在寻找的东西。 谷歌提供了大量的结果,但没有一个符合我的标准。

所以我在这里问: 是否有任何已知的代码可以创建一个可预测的,看起来是随机的,并且基于'种子'(在我的情况下是unix时间戳)并且在指定范围之间?

我希望能够在脚本中为我正在编码的游戏创建天气预报(但我需要可以移植的C ++代码,我不认为这里有很多人熟悉'PAWN'[aka SMALL]脚本语言?:))。 天气ID从0到100不等,包括一些弃用的ID(所以我的解决方案是制作一个包含有效天气ID的数组,这样我们就不用担心那些BAD_ID了,不要让功能过于复杂)。 / p>

我可能会制作这样的公式,但过去我遇到的问题是天气变化太快(就像每一秒,虽然我丢失了某处的代码:/)而且现在我真的没有想法我将如何制作这样的公式。

任何建议也非常感谢!

7 个答案:

答案 0 :(得分:2)

首先考察srandrand

C ++ 11也包含许多更高级的算法,但是对于基本需求,上面两个就足够了。

要将数字保持在0到n的范围内,请使用%运算符。

答案 1 :(得分:2)

显然,一个数字不能同时是“可预测的”和“随机的” - 这些都是直接矛盾的术语。

我假设你的意思是一个既是确定性又是半随机的数字。

幸运的是,这就是伪随机数生成器(PRNG)产生的结果:当它们使用一致的种子运行时,它们会为您提供相同的输出。

因此,我建议您使用srandom设置种子,然后使用random() % MAX_VALUE获取0到MAX_VALUE之间的数字。如果你得到“坏价值”,那就再去吧。重复播种不需要的数字。

答案 2 :(得分:2)

查看random number generator used by VB6的C实现。它非常适合游戏,因为它可以产生相当可信的随机序列但是使用种子并且相同的种子总是生成相同的序列。因此,在游戏数据文件中,您可以保存一组种子值,这些种子值将为您提供可以轻松复制的已知(但随机查看)序列。

这是一个返回范围内值的实现:

typedef int Int32;
typedef unsigned int UInt32;

class CRnd
{
    private:
        static const UInt32 INITIAL_VALUE = 0x50000;
        static const UInt32 INCREMENT = 0xC39EC3;
        static const UInt32 MULTIPLIER = 0x43FD43FD;

    private:
        UInt32 m_nRnd;

    public:
        CRnd () { m_nRnd = INITIAL_VALUE; };
        CRnd ( IN UInt32 nSeed ) { m_nRnd = nSeed; };
        virtual ~CRnd () {};

        Int32 Get ( IN Int32 nFrom, IN Int32 nTo )
        {
            if ( nTo < nFrom ) // nFrom should be less than nTo
            {
                Int32 nTmp = nTo;

                nTo = nFrom;
                nFrom = nTmp;
            }
            else if ( nTo == nFrom )
            {
                return ( nTo );
            }

            m_nRnd = ( m_nRnd * MULTIPLIER + INCREMENT ) & 0xFFFFFF;

            float fTmp = (float) m_nRnd / (float) 16777216.0;

            return ( (Int32) ( ( fTmp * ( nTo - nFrom + 1 ) ) + nFrom ) );
        };

        void SetSeed ( IN UInt32 nSeed ) { m_nRnd = nSeed; };
        UInt32 GetSeed () { return ( m_nRnd ); };
};

答案 3 :(得分:1)

如果您需要缓慢变化的值,可以使用噪音功能,例如Perlin Noise

答案 4 :(得分:0)

你真正想要的是哈希函数。要限制范围,您可以使用常用技巧之一(最脏的是余数运算符)。

具体来说,您希望将整数散列为整数。你可以选择这样一个函数here。我推荐一个标题为“罗伯特詹金斯'32位整数散列函数” - 一直对我很好。

你最终会得到类似的东西:

int time_index = 3;
int weather_state = integer_hash_function(time_index) % (MAX_VALUE - MIN_VALUE + 1) + MIN_VALUE

如果您想要更有趣的天气行为,可以在时间值之间进行线性插值。您可以将Perlin噪声与不同频率和强度的内插噪声的线性组合结合使用,以产生一些相当不错的行为。 (我用多人RPG做了这个,效果很好。)

答案 5 :(得分:0)

srandrand的问题在于,只有他们的呼叫签名(而不是他们生成的值)才由C标准规定。如果您需要便携式确定性伪随机数,则应自行实施。这是一个用C ++编写的类,它基于Numerical Recipes中的一个类,并且是完全可移植的。如果您愿意,可以使用种子实例化随机数流。我硬编码这个种子,而不是使用时间,以防我一次又一次地想要相同的伪随机序列。您还可以使用RandomInteger(a,b)方法在半开区间[a,b]上获取整数。

class RandomNumberStream
{
private:
  unsigned long long u,v,w;

public:
  RandomNumberStream(int n=1);
  double RandomDouble();
  double RandomDouble(double a, double b);
  unsigned long long RandomInteger();
  unsigned long long RandomInteger(int a, int b);
private:
  unsigned long long int64();
} ;



RandomNumberStream::RandomNumberStream(int n)
{
  v = 4101842887655102017LL;
  w = 1;

  u = n^v; int64();
  v =   u; int64();
  w =   v; int64();
}
double RandomNumberStream::RandomDouble()
{
  return int64() * 5.42101086242752217E-20f;
}
double RandomNumberStream::RandomDouble(double a, double b)
{
  return int64() * 5.42101086242752217E-20f * (b-a) + a;
}
unsigned long long RandomNumberStream::RandomInteger()
{
  return int64();
}
unsigned long long RandomNumberStream::RandomInteger(int a, int b)
{
  return a + int64() % (b-a);
}
unsigned long long RandomNumberStream::int64()
{
  u  = u * 2862933555777941757LL + 7046029254386353087LL;
  v ^= v>>17; v ^= v<<31; v ^= v>>8;
  w  = 4294957665U*(w & 0xffffffff) + (w>>32);
  unsigned long long x = u^(u<<21); x ^= x>>35; x ^= x<<4;
  return (x+v)^w;
}

答案 6 :(得分:0)

我认为您可以使用rand生成随机数。但是,您可以给出相同的值,例如99,这样您的数字将是随机的,但每次都可以预测。

int iSecret = 0;

/* initialize random seed: */
srand ( 99 );

/* generate secret number: */
iSecret = rand();