伪随机函数整理及使用

一.常用随机方法:

官方推荐使用的函数为 :
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

};

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值