一.常用随机方法:
官方推荐使用的函数为 :
long int random(void);
返回 0 ------- RAND_MAX 之间的一个 long 类型整数,该函数会产生一个非常大的随机值,最大为 16*((2**31)-1)。
random 函数使用非线性反馈随机数发生器生成默认大小为31个长整数表所返回的连续伪随机数。
void srandom(unsigned int seed);
设置种子值,一般与“当前时间 + 进程ID”作为种子,如果没用调用该函数,则通过random返回的默认种子值为1。
也就是不建议用srand和rand函数
一般随机方式都是:
1. 进程开始的时候使用srandom(time(NULL)) 设置随机算子 ,即使是多线程情况下也是在线程开启前设置
2. 在每个使用位置使用random() % num 的方式获得随机值(一般*10000 像这样乘以一个比较大的只已增加平衡度)
3.如果是多线程的话,需要加锁,因为random不是线程安全的
其他随机模板: (参考下边例子)
1. random_shuffle 随机重排
2. random_sample 随机抽样
3. random_sample_n 顺序随机抽样
如1: 随机文案:
boost::mutex random_mutex;
// 随机一个文案
uint32_t num = getCfg.desc.size(); // 获取文案个数
uint32_t num_max = num * 10000 ; // 扩大随机平衡度
{
boost::mutex::scoped_lock lock(LotterySrv::Instance().random_mutex); // 加锁
num = (random() % num_max) / 10000; // 随机
}
string strDesc = getCfg.desc[num]; // 获取文案
如2:随机map中的数据模板
template<typename T>
inline T& randomMap( map< uint32_t, T > input, boost::mutex &random_mutex )
{
typename map< uint32_t, T >::reverse_iterator rit = input.rbegin();
if( input.empty() )
{
logth( Error, "%s, %s, empty random table", __FUNCTION__, log_str.c_str() );
static T null_t;
return null_t;
}
uint32_t random_out = 0;
{
boost::mutex::scoped_lock lock( random_mutex ); // 加锁
random_out = random() % max; // 随机
}
typename map< uint32_t, T >::iterator it = input.upper_bound( random_out ); // 获取第一个key大于random_out 的数据
logth( Info, "%s, max : %u, out : %u, catch : %u", __FUNCTION__, max, random_out, it->first );
return input.upper_bound( random_out )->second;
}
random_shuffle 随机重排
(1)template <class RandomAccessIterator>
void random_shuffle(RandomAccessIterator first,RandomAccessIterator last);
(2)template <class RandomAccessIterator,class RandomNumberGenerator>
void random_shuffle(RandomAccessIterator first,RandomAccessIterator last,RandomNumberGenerator& rand);
算法random_shuffle随机重排[first,last)的顺序,即它在N!种可能的元素排列顺序中随机选出一种。N个元素的序列其排列方式有N!种,而random_shuffle会产生一种均匀分布。版本1使用了内部的乱数产生器,版本2则使用了特别的函数对象RandomNumberGenerator ,它被当成引数传递进来,而非值传递。如果乱数的选择对您的程序很重要那么请选择第二版本。
【举例】随机排列数组
int main(){
const int N=8;
int A[]={1,2,3,4,5,6,7,8};
random_shuffle(A,A+N);
copy(A,A+N,ostream_iterator<int>(cout," "));
cout<<endl; //输出结果可能是 7 1 6 4 3 2 5 8 或8!=40319种其他可能性之一。
}
random_sample 随机抽样
(1)template <class InputIterator,class RandomAccessIterator>
RandomAccessIterator random_sample(InputIterator first,InputIterator last,RandomAccessIterator ofirst,RandomAccessIterator olast);
(2)template <class InputIterator,class RandomAccessIterator,class RandomNumberGenerator>
RandomAccessIterator random_sample(InputIterator first,InputIterator last,RandomAccessIterator ofirst,RandomAccessIterator olast,RandomNumberGenerator& rand);
算法random_sample 会随机选择[first,last)内的一个取样结果复制到[ofist,olast)中,它会复制n个元素(n是min{last-fist,olast-ofirst}),取样结果是均匀分布的。注意:random_sample无法保持元素的相对顺序。
【举例】随机抽样数组
int main(){
const int N=8;
const int n=4;
int A[]={1,2,3,4,5,6,7,8};
int B[n];
random_sample(A,A+N,B,B+n);
copy(B, B+n,ostream_iterator<int>(cout," "));
cout<<endl; //输出结果可能是 1 6 8 4 或5039种其他可能性之一。
}
random_sample_n 随机抽样(顺序)
(1)template <class ForwardIterator,class OutputIterator,class Distance>
OutputIterator random_sample_n(ForwardIterator first,ForwardIterator last,OutputIterator out,Distance n);
(2)template <class ForwardIterator,class OutputIterator,class Distance,class RandomNumberGenerator>
OutputIterator random_sample_n(ForwardIterator first,ForwardIterator last,OutputIterator out,Distance n,RandomNumberGenerator& rand);
同random_sample.它能够随机将[first,last)中的某些元素复制到[out,out+n)中,它会复制m个元素,m为min{last-first,n},以均匀分布的方式取样。不同于random_sample的是,random_sample_n会保持元素的相对顺序。
【举例】随机抽样数组
int main(){
const int N=8;
int A[]={1,2,3,4,5,6,7,8};
random_sample_n(A,A+N,ostream_iterator<int>(cout," "),4);
cout<<endl; //输出结果可能是3 5 6 8 或209种其他可能性之一。
}
梅森旋转算法:生成伪随机数
namespace uck{
class twisting_mersenne_rng
{
public:
// 构造函数,创建并初始化随机算子
twisting_mersenne_rng()
{
static time_t seed = _InitSeed();
m_lock = 0;
_FillRand();
}
virtual ~twisting_mersenne_rng(void)
{
}
// 随机返回中的一个值
// Can't support float/double/int64_t/uint64_t for now
template<typename _Ty> _Ty roll(_Ty from = 0, _Ty to = ~0)
{
if (from == to)
{
return from;
}
else if (from > to)
{
from ^= to;
to ^= from;
from ^= to;
}
uint32_t index;
// 当一轮取完之后重新生成随机值,一轮623个值
while ((index = __sync_fetch_and_add(&m_index, 1)) >= 623)
{
while (!__sync_bool_compare_and_swap(&m_lock, 0, 1));
if (m_index != 0)
{
_FillRand();
}
__sync_fetch_and_sub(&m_lock, 1);
}
// 按顺序取出m_randims中的随机值
return (_Ty)(double(m_randoms[index]) / (double(uint32_t(~0)) + 1) * double(to - from + 1)) + from;
}
private:
time_t _InitSeed()
{
time_t t = time(0);
srand(t);
return t;
}
// Mersenne twister
void _FillRand()
{
// 用一个种子初始化发生器
m_randoms[0] = rand();
// 梅森算法核心
for (uint32_t i = 1; i < 624; i++)
{
m_randoms[i] = (1812433253 * (m_randoms[i-1] ^ (m_randoms[i-1] >> 30)) + i); // 0x6c078965
}
// Generate an array of 624 untempered numbers
for (uint32_t i = 0; i < 623; i++)
{
uint32_t y = (m_randoms[i] & 0x80000000) // bit 31 (32nd bit) of MT[i]
+ (m_randoms[(i+1) % 624] & 0x7fffffff); // bits 0-30 (first 31 bits) of MT[...]
m_randoms[i] = m_randoms[(i + 397) % 624] ^ (y >> 1);
if (y % 2 != 0) // y is odd
{
m_randoms[i] ^= 0x9908b0df; // 0x9908b0df
}
// Extract a tempered pseudorandom number based on the index-th value,
// calling generate_numbers() every 624 numbers
y = m_randoms[i];
y = y ^ (y >> 11);
y = y ^ ((y << 7) & 2636928640);
y = y ^ ((y << 15) & 4022730752);
y = y ^ (y >> 18);
m_randoms[i] = y;
}
__sync_and_and_fetch(&m_index, 0);
}
// template<> float roll(float from, float to) { return 0.0f; }
// template<> double roll(double from, double to) { return 0.0f; }
// template<> int64_t roll(int64_t from, int64_t to) { return 0; }
// template<> uint64_t roll(uint64_t from, uint64_t to) { return 0; }
volatile uint32_t m_lock; // 锁
volatile uint32_t m_index; // 读取标记
uint32_t m_randoms[624]; //624 * 32 - 31 = 19937
};
}