【问题标题】:Why does uniform_int_distribution<uintmax_t> work for 62 bit numbers but not for 63 or 64 bit ones?为什么 uniform_int_distribution<uintmax_t> 适用于 62 位数字但不适用于 63 或 64 位数字?
【发布时间】:2011-10-27 14:47:00
【问题描述】:

我很难理解为什么这段代码(尝试在 C++11 中使用新的 &lt;random&gt; 标头)在 [0, 2**62 - 1] 中正确生成随机数,而不是在 [0, 2**63 - 1][0, 2**64 - 1] 中生成随机数。

#include <iostream>
#include <stdint.h>
#include <random>
#include <functional>
#include <ctime>

static std::mt19937 engine; // Mersenne twister MT19937

void print_n_random_bits (unsigned int n);

int main (void) {
  engine.seed(time(0));
  print_n_random_bits(64);
  print_n_random_bits(63);
  print_n_random_bits(62);
  return 0;
}

void print_n_random_bits (unsigned int n)
{
  uintmax_t max;

  if (n == 8 * sizeof(uintmax_t)) {
    max = 0;
  } else {
    max = 1;
    max <<= n;
  }
  --max;

  std::uniform_int_distribution<uintmax_t> distribution(0, max);

  std::cout << n << " bits, max: " << max << std::endl;
  std::cout << distribution(engine) << std::endl;
}

现在,进一步挖掘发现 std::mt19937_64,它具有正确的行为,但谁能向我解释为什么适用于 62 位数字的东西不适用于 64 位数字?

编辑:抱歉,我什至没有具体说明问题所在。 问题在于,对于 63 位和 64 位最大值,输出始终是 [0, 2**32 - 1] 范围内的数字,例如:

% ./rand                       
64 bits, max: 18446744073709551615
1803260654
63 bits, max: 9223372036854775807
3178301365
62 bits, max: 4611686018427387903
2943926730538475327

% ./rand                                
64 bits, max: 18446744073709551615
1525658116
63 bits, max: 9223372036854775807
2093351390
62 bits, max: 4611686018427387903
1513326512211312260

% ./rand                                                       
64 bits, max: 18446744073709551615
884934896
63 bits, max: 9223372036854775807
683284805
62 bits, max: 4611686018427387903
2333288494897435595       

编辑 2:我正在使用 clang++ (Apple clang version 2.1 (tags/Apple/clang-163.7.1)) 和“libc++”。由于我的版本不支持c++0x,因此我无法使用 GCC 轻松测试上述内容。

【问题讨论】:

  • 它到底在做什么出乎意料?也就是说,它究竟如何为您提供与您的预期不同的结果?
  • 另外,您使用的是什么标准库实现?
  • 认为这可能只是运气不好:)
  • 使用 GCC4.5.1,所有三个测试(62/63/64 位)都返回 32 位值。 ideone.com/3GZ9S
  • 使用 GCC4.6.1,所有三个测试(62/63/64 位)都返回 64 位值。

标签: c++ c++11 libc++


【解决方案1】:

您在 libc++ 中发现了一个错误。谢谢!!!

我已对 143104 版本的树干尖端进行了以下修复:

Index: include/algorithm
===================================================================
--- include/algorithm   (revision 143102)
+++ include/algorithm   (working copy)
@@ -2548,7 +2548,7 @@
         {
             __u = __e_() - _Engine::min();
         } while (__u >= __y0_);
-        if (__w0_ < _EDt)
+        if (__w0_ < _WDt)
             _S <<= __w0_;
         else
             _S = 0;
@@ -2561,7 +2561,7 @@
         {
             __u = __e_() - _Engine::min();
         } while (__u >= __y1_);
-        if (__w0_ < _EDt - 1)
+        if (__w0_ < _WDt - 1)
             _S <<= __w0_ + 1;
         else
             _S = 0;

此修复不需要重新编译二进制 libc++.dylib。

【讨论】:

  • libc++ 中使用的算法是否有任何已知名称可供阅读?
  • 我不知道。该算法在 Independent_bits_engine 的标准规范中指定。
【解决方案2】:

由于std::mt19937 是 32 位版本,最有可能发生的事情是它在生成下一个数字时假设哪些位在其“工作空间”中重要和不重要。当生成可能包含最后两位的数字时,这会导致溢出。我怀疑您会发现实际分布并不均匀,最大数字高于 32 位引擎上的 2**32 - 1

【讨论】:

  • 对此不确定。简要调查表明,基于 1,000,000 个生成的整数,分布是均匀的或接近于该死的,最大值为 2**62 - 1
  • 即使mt19937返回32位数字,uniform_int_distribution不应该多次调用它来创建62/63/64位数字吗?
猜你喜欢
  • 2013-09-11
  • 1970-01-01
  • 2017-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多