【问题标题】:generate random 64 bit integer生成随机 64 位整数
【发布时间】:2011-11-14 10:15:57
【问题描述】:

我需要你的帮助,请给我一些建议。从编程珍珠中我知道要生成随机的 30 位整数,我们应该这样写:

RAND_MAX*rand()+rand()

但是我可以做些什么来生成不是 30 而是 64 位的随机整数呢?如果我将两个 30 位整数相乘,然后再乘以 4 位整数,我认为这是非常低效的方法,那么我应该使用哪种方法呢? 我现在对 64 位使用 popcount_1 不同的方法,我想在随机整数上对其进行测试(我也在测量每个人完成任务所需的时间)

【问题讨论】:

  • 你也可以移位和加起来..

标签: c++ random 64-bit


【解决方案1】:

首先,我对您发布的 30 位解决方案表示怀疑 整数。 RAND_MAX 本身可能是 31 位值,RAND_MAX * rand() + rand() 可能会溢出,产生未定义的行为 (实际上是负值)。

如果您需要一个大于保证最小值 RAND_MAX 的值,或者 就此而言,任何不明显小于 RAND_MAX,唯一的解决方案是使用连续调用 rand(),并结合这些值,但您需要仔细执行此操作,并且 验证结果。 (rand() 的大多数实现使用线性 一致的生成器,虽然足以完成某些任务,但不是 在这种情况下特别好。)无论如何,例如:

unsigned 
rand256()
{
    static unsigned const limit = RAND_MAX - RAND_MAX % 256;
    unsigned result = rand();
    while ( result >= limit ) {
        result = rand();
    }
    return result % 256;
}

unsigned long long
rand64bits()
{
    unsigned long long results = 0ULL;
    for ( int count = 8; count > 0; -- count ) {
        results = 256U * results + rand256();
    }
    return results;
}

(rand256 中的代码旨在消除其他情况 将 RAND_MAX 值映射到 256 个值时会出现不可避免的偏差。)

【讨论】:

  • 如何控制这段代码的精度。假设我想生成 61 位随机数而不是 64 位。我想如果我从 7 而不是 8 开始计数,我会得到一个 56 位的随机数。我说的对吗?
  • @arunmoezhi 如果可以生成64个随机位,可以通过生成64生成61,丢掉3个;例如通过屏蔽前三位。
  • 有道理。谢谢。您的解决方案看起来不错。但是如果你能添加一些解释会更有帮助。我花了一些时间才明白你在做什么。
【解决方案2】:

这可能是一个解决方案,无需乘法:

r30 = RAND_MAX*rand()+rand()
s30 = RAND_MAX*rand()+rand()
t4  = rand() & 0xf

res = (r30 << 34) + (s30 << 4) + t4

【讨论】:

  • 这假设 RAND_MAX 是 1确实假设这一点,为什么不:rand() + rand() &lt;&lt; 15 + rand() &lt;&lt; 30 + rand() &lt;&lt; 45 + (rand() &amp; 0xf) &lt;&lt; 60?根本没有乘法。
  • 为什么不直接做类似return ((unsigned long long)rand() &lt;&lt; 48) | ((unsigned long long)rand() &lt;&lt; 32) | ((unsigned long long)rand() &lt;&lt; 16) | ((unsigned long long)rand() &amp; 0xffff); 的事情呢?在这里你根本没有乘法,只有移位。
  • 虽然,是的,你可以生成 64 位。在我看来,生成的随机数的分辨率不能大于随机数种子。
  • 你说“没有乘法”,但那里有乘法。而且这不会均匀分布(例如,r30 可以等于RAND_MAX 有两种不同的方式)。当然,在许多实现中,RAND_MAX == 1&lt;&lt;15 的未说明假设并不正确。
【解决方案3】:

如果boost 是一个选项,您可以使用boost random

【讨论】:

  • 你确定它可以生成64位吗?您的链接另有说明:“mt19937 产生 [0, 2^32-1] 范围内的整数。”
  • 查看各种生成器 (boost.org/doc/libs/1_47_0/doc/html/boost_random/…),例如 ranlux64_3
  • @duedl0r 如果它确实在整个间隔[0, 2^32-1] 上生成了一个好的随机值,那么将两个调用组合起来生成一个好的 64 位随机值应该是相当简单的。 (当然,对于“好”的足够宽松的定义。基本生成器仍然需要 2^64 或更多的周期,否则将有很多值永远无法生成。)
  • 从统计学上讲,要生成所有值,您可能需要一个设计周期至少为 2^64 的生成器。实际上,对于大多数应用程序来说,一个简单的移位/乘法解决方案就可以很好地工作。
  • 使用默认选项 (mt19937),期间真的不是问题。 2^19937 比宇宙的寿命要长得多。
【解决方案4】:

随机 64 位 int 本质上是将 64 位随机位解释为 int。

用随机字节 (see here for how) 填充长度为 8 的字节数组,并将其解释为 int (see here for how)。

【讨论】:

  • 我怀疑在大多数rand() 的实现中,您不会通过这样做获得特别均匀的分布。
【解决方案5】:

通用解决方案:

template <unsigned long long I> struct log2 {
  static const int result = 1 + log2<I/2>::result;
};
template <> struct log2<1> {
  static const int result = 0;
};

template <typename UINT> UINT genrand() {
  UINT result = 0;
  int bits = std::numeric_limits<UINT>::digits;
  int rand_bits = log2<RAND_MAX>::result;
  while (bits > 0) {
    int r = rand();
    while (r >= (1<<rand_bits)) r = rand(); // Retry if too big.
    result <<= rand_bits;
    result += r;
    bits -= rand_bits;
  }
  return result;
}

使用:unsigned long long R = genrand&lt;unsigned long long&gt;();

bits 计数器跟踪仍需要的位数。

【讨论】:

    【解决方案6】:

    '返回一个介于​0​和 RAND_MAX(包括 0 和 RAND_MAX)之间的伪随机整数值。 - http://en.cppreference.com/w/cpp/numeric/random/rand

    因此,您应该使用 RAND_MAX + 1(这就像逐位生成一个数字,然后将其转换为以 10 为底)而不是 RAND_MAX。 通过这种方式,您可以生成以 RAND_MAX + 1 为底(可能带有前导零)的一位、两位、三位等数字,并将它们转换为以 10 为底的数字并获得任意大的数字。

    所有你获得的大于你想要的 MAX_VALUE 的东西都可以被丢弃,你仍然有 1/(MAX_VALUE + 1) 的概率获得每个数字。

    请注意,此方法可能需要一段时间,特别是如果您想要的 MAX_VALUE 远小于在丢弃不需要的数字之前可以获得的最大值,作为获得随机数的预期步骤数在 [0, MAX_VALUE] 中使用此算法为:(MAX_OBTAINABLE_VALUE + 1)/(MAX_VALUE + 1)

    【讨论】:

      猜你喜欢
      • 2016-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-05
      • 2014-12-20
      • 1970-01-01
      • 2020-10-01
      • 1970-01-01
      相关资源
      最近更新 更多