C++ 随机但可预测的数字生成器?[C+;+;]
嗯,我真的不知道如何寻找我要找的东西。 谷歌给出了大量的结果,但没有一个符合我的标准 所以我在这里问: 是否有任何已知的代码段可以创建一个数字,该数字是可预测的,看起来是随机的,并且基于一个“种子”(在我的例子中是unix时间戳),并且在指定的范围内 我希望能够为我编写的游戏编写脚本中的天气预报(但我需要C++代码,我可以把它移植到端口上,我想这里的很多人都不熟悉‘典当’[A.K.Asia]脚本语言:))。 天气id从0到~100不等,包括一些不推荐使用的id(因此我的解决方案是制作一个包含有效天气id的数组,这样我们就不必担心那些坏id,让我们不要使函数太复杂) 我可能会得出这样的公式,但过去我遇到的问题是天气变化太快(就像每秒钟一样,尽管我在某处丢失了代码:/),现在我真的不知道如何得出这样的公式C++ 随机但可预测的数字生成器?[C+;+;],c++,random,formula,weather,forecasting,C++,Random,Formula,Weather,Forecasting,嗯,我真的不知道如何寻找我要找的东西。 谷歌给出了大量的结果,但没有一个符合我的标准 所以我在这里问: 是否有任何已知的代码段可以创建一个数字,该数字是可预测的,看起来是随机的,并且基于一个“种子”(在我的例子中是unix时间戳),并且在指定的范围内 我希望能够为我编写的游戏编写脚本中的天气预报(但我需要C++代码,我可以把它移植到端口上,我想这里的很多人都不熟悉‘典当’[A.K.Asia]脚本语言:))。 天气id从0到~100不等,包括一些不推荐使用的id(因此我的解决方案是制作一个包含有效
任何建议都非常感谢 首先查看
srand
和rand
C++11还包括许多更高级的算法,但对于基本需求来说,上面两个就足够了
要将数字保持在0到n的范围内,请使用
%
运算符。显然,数字不能同时是“可预测”和“随机”的-它们是直接矛盾的术语
我假设你的意思是一个既确定又半随机的数字
幸运的是,这就是伪随机数生成器(PRNG)产生的结果:当它们使用一致的种子运行时,它们会提供相同的输出
因此,我建议使用
srandom
设置种子,然后使用random()%MAX\u VALUE
获得一个介于0和MAX\u VALUE
之间的数字。如果你得到一个“坏值”,就再去一次。对任意数量的数字重复SAN重新设定种子。如果需要缓慢变化的值,可以使用噪波函数,例如。真正需要的是哈希函数。要限制范围,可以使用常用技巧之一(最脏的是余数操作符)
具体来说,您希望将整数散列为整数。你可以选择这样一个函数。我推荐一个名为“Robert Jenkins的32位整数哈希函数”的函数,它对我来说总是很好用
你最终会得到这样的结果:
int time_index = 3;
int weather_state = integer_hash_function(time_index) % (MAX_VALUE - MIN_VALUE + 1) + MIN_VALUE
如果想要更有趣的天气行为,可以在时间值之间进行线性插值。您可以将柏林噪声与这种插值噪声在不同频率和强度下的线性组合使用,以产生一些非常好的行为。(我已经用多人RPG完成了这项工作,它工作得很好。)看看的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 ); };
};
typedef int Int32;
typedef无符号整数UInt32;
类CRnd
{
私人:
静态常数UInt32初始值=0x50000;
静态常数UInt32增量=0xC39EC3;
静态常数UInt32乘数=0x43FD43FD;
私人:
UInt32米;
公众:
CRnd(){m_nRnd=初始值;};
CRnd(在UInt32 nSeed中){m_nRnd=nSeed;};
虚拟~CRnd(){};
Int32 Get(在Int32 nFrom中,在Int32 nTo中)
{
if(nTo与srand
和rand
相关的问题在于,只有它们的调用签名(而不是它们生成的值)由C标准规定。如果您需要可移植的确定性伪随机数,您应该自己实现它。这里是一个C++语言的课堂,它是基于数字食谱中的一个,完全是可移植的。如果愿意,可以用种子实例化随机数流。我硬编码这个种子,而不是使用时间,以防我一次又一次地想要相同的伪随机序列。您还可以使用randominger(a,b)
方法获取半开区间[a,b]上的整数
类随机数流
{
私人:
无符号长u、v、w;
公众:
随机数流(int n=1);
双随机双();
双随机双(双a,双b);
无符号长随机整数();
无符号长随机整数(int a,int b);
私人:
无符号long-long int64();
} ;
RandomNumberStream::RandomNumberStream(int n)
{
v=410184288765102017LL;
w=1;
u=n^v;int64();
v=u;int64();
w=v;int64();
}
double RandomNumberStream::RandomDouble()
{
返回int64()*5.42101086242752217E-20f;
}
double RandomNumberStream::RandomDouble(双a,双b)
{
返回int64()*5.42101086242752217E-20f*(b-a)+a;
}
无符号长随机数流::随机整数()
{
返回int64();
}
无符号长随机数流::随机整数(int a,int b)
{
返回a+int64()%(b-a);
}
无符号长随机数流::int64()
{
u=u*286293355577941757LL+7046029254386353087LL;
v^=v>>17;v^=v8;
w=
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;
}
int iSecret = 0;
/* initialize random seed: */
srand ( 99 );
/* generate secret number: */
iSecret = rand();