我需要在性能关键路径上生成随机布尔值。
我为此写的代码是
std::random_device rd;
std::uniform_int_distribution<> randomizer(0, 1);
const int val randomizer(std::mt19937(rd()));
const bool isDirectionChanged = static_cast<bool>(val);
但是不要认为这是最好的方法,因为我不喜欢static_cast<bool>
。
在网络上我找到了更多解决方案
1. std::bernoulli_distribution
2. bool randbool = rand() & 1;
请务必在开头致电srand()
。
答案 0 :(得分:39)
出于演出目的,价格低于“随机性”的价格。 std::mt19937_64
,您可以使用Xorshift+生成64位数字,然后将这些数字的位用作伪随机布尔值。
引用维基百科:
这个生成器是传递BigCrush的最快的生成器之一
详细信息:http://xorshift.di.unimi.it/。页面中间有一个比较表,显示mt19937_64
慢2倍且系统化。
下面是示例代码(真正的代码应该将它包装在一个类中):
#include <cstdint>
#include <random>
using namespace std;
random_device rd;
/* The state must be seeded so that it is not everywhere zero. */
uint64_t s[2] = { (uint64_t(rd()) << 32) ^ (rd()),
(uint64_t(rd()) << 32) ^ (rd()) };
uint64_t curRand;
uint8_t bit = 63;
uint64_t xorshift128plus(void) {
uint64_t x = s[0];
uint64_t const y = s[1];
s[0] = y;
x ^= x << 23; // a
s[1] = x ^ y ^ (x >> 17) ^ (y >> 26); // b, c
return s[1] + y;
}
bool randBool()
{
if(bit >= 63)
{
curRand = xorshift128plus();
bit = 0;
return curRand & 1;
}
else
{
bit++;
return curRand & (1<<bit);
}
}
答案 1 :(得分:18)
一些快速基准(code):
XorShift128PlusBitShifterPseudoRandomBooleanGenerator
对于那些想要使用现成代码的人,我会从上面的链接中提出RandomizerXorshiftPlus
,class XorShift128PlusBitShifterPseudoRandomBooleanGenerator {
public:
bool randBool() {
if (counter == 0) {
counter = sizeof(GeneratorType::result_type) * CHAR_BIT;
random_integer = generator();
}
return (random_integer >> --counter) & 1;
}
private:
class XorShift128Plus {
public:
using result_type = uint64_t;
XorShift128Plus() {
std::random_device rd;
state[0] = rd();
state[1] = rd();
}
result_type operator()() {
auto x = state[0];
auto y = state[1];
state[0] = y;
x ^= x << 23;
state[1] = x ^ y ^ (x >> 17) ^ (y >> 26);
return state[1] + y;
}
private:
result_type state[2];
};
using GeneratorType = XorShift128Plus;
GeneratorType generator;
GeneratorType::result_type random_integer;
int counter = 0;
};
的调整版本。在我的机器上,它与@ SergeRogatch的解决方案一样快,但在循环计数高(≳100,000)时一直快10-20%,在循环次数较少的情况下慢约30%。 / p>
class Float
def round_half_to_even(precision)
if self % 1 == 0.5
floor = self.to_i.to_f
return floor % 2 == 0 ? floor : floor + 1
else
return self.round(precision)
end
end
end
答案 2 :(得分:10)
一种方法是仅为评论中所述的每64个随机调用生成unsigned long long
。一个例子:
#include <random>
class Randomizer
{
public:
Randomizer() : m_rand(0), counter(0), randomizer(0, std::numeric_limits<unsigned long long>::max()) {}
bool RandomBool()
{
if (!counter)
{
m_rand = randomizer(std::mt19937(rd()));
counter = sizeof(unsigned long long) * 8;
}
return (m_rand >> --counter) & 1;
}
private:
std::random_device rd;
std::uniform_int_distribution<unsigned long long> randomizer;
unsigned long long m_rand;
int counter;
};
答案 3 :(得分:4)
我会预先填充64位随机值的(足够长的)(循环)缓冲区,然后在需要布尔随机值时一次非常快速地取一个位
#include <stdint.h>
class BoolGenerator {
private:
const int BUFFER_SIZE = 65536;
uint64_t randomBuffer[BUFFER_SIZE];
uint64_t mask;
int counter;
void advanceCounter {
counter++;
if (counter == BUFFER_SIZE) {
counter = 0;
}
}
public:
BoolGenerator() {
//HERE FILL YOUR BUFFER WITH A RANDOM GENERATOR
mask = 1;
counter = 0;
}
bool generate() {
mask <<= 1;
if (!mask) { //After 64 shifts the mask becomes zero
mask = 1;//reset mask
advanceCounter();//get the next value in the buffer
}
return randomBuffer[counter] & mask;
}
}
当然这个类可以通用于缓冲区大小,随机生成器,基类型(不一定是uint64_t)等。
每64次调用仅访问一次缓冲区:
#include <stdint.h> //...and much more
class BoolGenerator {
private:
static const int BUFFER_SIZE = 65536;
uint64_t randomBuffer[BUFFER_SIZE];
uint64_t currValue;
int bufferCounter;
int bitCounter;
void advanceBufferCounter() {
bufferCounter++;
if (bufferCounter == BUFFER_SIZE) {
bufferCounter = 0;
}
}
void getNextValue() {
currValue = randomBuffer[bufferCounter];
bitCounter = sizeof(uint64_t) * 8;
advanceBufferCounter();
}
//HERE FILL YOUR BUFFER WITH A RANDOM GENERATOR
void initializeBuffer() {
//Anything will do, taken from here: http://stackoverflow.com/a/19728404/2436175
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<uint64_t> uni(0,std::numeric_limits<uint64_t>::max());
for (int i = 0; i < BUFFER_SIZE; i++ ) {
randomBuffer[i] = uni(rng);
}
}
public:
BoolGenerator() {
initializeBuffer();
bufferCounter = 0;
getNextValue();
}
bool generate() {
if (!bitCounter) {
getNextValue();
}
//A variation of other methods seen around
bitCounter--;
bool retVal = currValue & 0x01;
currValue >>= 1;
return retVal;
}
};
答案 4 :(得分:3)
除非你对所需的随机性有进一步的限制,否则生成随机bool的最快方法是:
bool RandomBool() { return false; }
更具体地说,有数千种方法可以生成随机布尔值,所有这些方法都满足不同的约束条件,而且其中许多方法都不能提供“真正的”随机数(到目前为止包含所有其他答案)。单词“随机”并不能告诉任何人你真正需要什么属性。
答案 5 :(得分:1)
如果效果是您唯一的标准,那么answer就是:
bool get_random()
{
return true; // chosen by fair coin flip.
// guaranteed to be random.
}
不幸的是,这个随机数的熵是零,但性能非常快。
由于我怀疑这个随机数生成器对你不是很有用,你需要量化你希望你的布尔值是多么随机。 2048的周期长度怎么样?一百万? 2 ^ 19937-1?直到宇宙结束?
我怀疑,既然你明确表示性能是你最关心的问题,那么一个好的老式线性同余生成器可能“足够好”。基于this article,我猜这个生成器的周期大约是32 *((2 ^ 31)-5),或大约68万亿次迭代。如果那不是“足够好”,你可以放入你喜欢的任何C ++ 11兼容的生成器而不是minstd_rand。
要获得额外的功劳,并且效果不佳,请修改以下代码,以使用biased coin algorithm消除生成器中的偏差。
#include <iostream>
#include <random>
bool get_random()
{
typedef std::minstd_rand generator_type;
typedef generator_type::result_type result_type;
static generator_type generator;
static unsigned int bits_remaining = 0;
static result_type random_bits;
if ( bits_remaining == 0 )
{
random_bits = generator();
bits_remaining = sizeof( result_type ) * CHAR_BIT - 1;
}
return ( ( random_bits & ( 1 << bits_remaining-- ) ) != 0 );
}
int main()
{
for ( unsigned int i = 0; i < 1000; i++ )
{
std::cout << " Choice " << i << ": ";
if ( get_random() )
std::cout << "true";
else
std::cout << "false";
std::cout << std::endl;
}
}
答案 6 :(得分:0)
我认为最好的方法是使用预先计算的随机数组:
uint8_t g_rand[UINT16_MAX];
bool InitRand()
{
for (size_t i = 0, n = UINT16_MAX; i < n; ++i)
g_rand[i] = ::rand() & 1;
return true;
}
bool g_inited = InitRand();
inline const uint8_t * Rand()
{
return g_rand + (::rand()&INT16_MAX);
}
用于填充某些数组dst [size]:
const size_t size = 10000;
bool dst[size];
for (size_t i = 0; i < size; i += INT16_MAX)
memcpy(dst + i, Rand(), std::min<size_t>(INT16_MAX, size - col));
当然,您可以使用另一个随机函数初始化预先计算的数组。
答案 7 :(得分:0)
如果性能很重要,或许最好生成一个32位随机数并使用它的每个单独位,如下所示:
bool getRandBool() {
static uint32_t randomnumber;
static int i=0;
if (i==0) {
randomnumber = <whatever your favorite randonnumbergenerator is>;
i=32;
}
return (randomnumber & 1<<--i);
}
这种方式只会影响每第32次呼叫
答案 8 :(得分:0)
显然我必须添加另一个答案。刚刚发现从Ivy Bridge架构开始,英特尔增加了RdRand CPU指令,AMD在2015年6月晚些时候添加了它。所以如果你的目标是处理器足够新并且不介意使用(内联)汇编,生成随机bool
的最快方法应该是调用RdRand
CPU指令来获取一个64位随机数,如here所述(滚动到大约中间位置)代码示例页面(在该链接上还有一个代码示例,用于检查当前CPU是否支持RdRand指令,另请参阅Wikipedia以获取有关如何使用CPUID指令执行此操作的说明),然后使用我的Xorshit+ based answer中描述的布尔数字。