【问题标题】:quickest way to generate random bits生成随机位的最快方法
【发布时间】:2010-10-26 10:32:58
【问题描述】:

生成大量(伪)随机位的最快方法是什么。每个位必须是独立的,并且以相等的概率为零或一。我显然可以在

上做一些变化
randbit=rand()%2;

但我觉得应该有一种更快的方法,从每次调用随机数生成器生成几个随机位。理想情况下,我希望得到一个 int 或 char,其中每个位都是随机且独立的,但其他解决方案也是可能的。

该应用程序本质上不是加密的,因此强随机性不是主要因素,而速度和获得正确的分布很重要。

【问题讨论】:

  • 您在寻找哪种发行版?你对分布的正确性有多挑剔。如果您真的希望区间 [1..n] 中的数字 x 的 P[x] = 1/n,那么即使您的应用程序不是加密的,您仍然需要一个好的 rng。
  • ((int)rand*rand)%2 这样的东西怎么样?
  • 可能与 stackoverflow.com/questions/25176423/… 重复(这个问题更广泛,因为它还询问非 50:50 分布)

标签: c++ random


【解决方案1】:

将随机数转换为二进制
为什么不只获取一个数字(大小合适以获取所需的足够位),然后将其转换为二进制。您实际上会从一个随机数中获得位,这意味着它们也是随机的。

0 和 1 的概率也为 50%,因为取 0 到 2^n 限制之间的所有数字并计算 0 和 1 的数量相等 > 意味着 0 和 1 的概率是相同的。

关于速度
这可能会非常快,因为与其中的位数相比,仅获得一个随机数会更快。它现在完全取决于您的二进制转换。

【讨论】:

  • 简短说明:二进制转换可能是一个简单的位移循环:for ( i = 0; i < sizeof( randomNumber ) * 8; ++i ) { std::cout << ( randomNumber & 1U ); randimNumber >>= 1U; } 假设 randomNumber 是一个无符号整数。
【解决方案2】:

看看Boost.Random,尤其是boost::uniform_int<>

【讨论】:

    【解决方案3】:

    正如你所说,只生成随机整数。
    然后你有 32 个随机位,其中 1 和 0 的概率相同。

    循环获取位:

    for (int i = 0; i < 32; i++)
    {
      randomBit = (randomNum >> i) & 1
      ...
      // Do your thing
    }
    

    重复此操作多次以获得正确的位数。

    【讨论】:

    • rand 不能保证返回 32 个随机位。其实在msvc下,它只返回16。
    • 当然是平台相关的,但是不管平台原理都是一样的。
    • 它们真的分布均匀吗?我考虑过这个想法,但不能完全说服自己每一位都会平等且独立地分布。
    • 这取决于位数。在较小的子集中,您可以找到偏态分布,但集合越大,分布就越均匀。由于您特别想要大量位,这应该满足您的分配正确性。
    • 常见的 RNG 具有完全非随机的 LSB(总是翻转)。
    【解决方案4】:

    这是我基于 George Marsaglia 的 XORShift 算法用 Java 编写的一个非常快的代码:一次获取 64 位!

    /**
     * State for random number generation
     */
    private static volatile long state=xorShift64(System.nanoTime()|0xCAFEBABE);
    
    /**
     * Gets a long random value
     * @return Random long value based on static state
     */
    public static final long nextLong() {
        long a=state;
        state = xorShift64(a);
        return a;
    }
    
    /**
     * XORShift algorithm - credit to George Marsaglia!
     * @param a Initial state
     * @return new state
     */
    public static final long xorShift64(long a) {
        a ^= (a << 21);
        a ^= (a >>> 35);
        a ^= (a << 4);
        return a;
    }
    

    【讨论】:

    • 注意:这个算法之所以这么快,是因为它只使用简单的位运算符,在一个已经被证明(Marsaglia)的序列中生成一个“足够好”的伪随机序列。这在密码学上强,但对于游戏、模拟等来说已经足够了。
    【解决方案5】:

    SMP Safe (i.e. Fastest way possiable these days) and good bits

    注意[ThreadStatic]属性的使用,这个对象自动处理新线程的,不加锁。这是确保高性能随机 SMP 无锁的唯一方法。

    http://blogs.msdn.com/pfxteam/archive/2009/02/19/9434171.aspx

    【讨论】:

      【解决方案6】:

      如果我没记错的话,最低有效位通常具有“较少随机性” 大多数伪随机数生成器的分布,因此如果您担心分布,使用模数和/或生成数字中的每个位会很糟糕。

      (也许您至少应该在谷歌上搜索一下 Knuth 所说的内容......)

      如果这成立(如果不确切知道您使用的是什么算法就很难判断),只需使用每个生成数字中的最高位。

      http://en.wikipedia.org/wiki/Pseudo-random

      【讨论】:

        【解决方案7】:
        #include <iostream>
        #include <bitset>
        #include <random>
        
        int main()
        {
            const size_t nrOfBits = 256;
            std::bitset<nrOfBits> randomBits;
        
            std::default_random_engine generator;
            std::uniform_real_distribution<float> distribution(0.0,1.0);
        
            float randNum;
            for(size_t i = 0; i < nrOfBits; i++)
            {
                randNum = distribution(generator);
                if(randNum < 0.5) {
                    randNum = 0;
                } else {
                    randNum = 1;
                }
                randomBits.set(i, randNum);
            }
        
            std::cout <<  "randomBits =\n" << randomBits << std::endl;
            return 0;
        }
        

        这在我的 256 位测试中耗时 4.5886e-05s。

        【讨论】:

        • 我喜欢这个答案,因为它是唯一一个展示 C++ 方式的答案,但我认为使用 bernoulli_distribution 会更好、更简单、更快、更正确!
        • @mxmlnkn 你为什么这么认为?
        • 因为您无需生成一个完整的 32 位浮点数并对其进行比较,而是从高度优化的 STL 对象中获取一个随机位,并且还保存了一些代码行,因为它归结为:std::bernoulli_distribution bdist(0.5); for(size_t i = 0; i &lt; nrOfBits; i++) randomBits.set(i, bdist(generator));
        【解决方案8】:

        您可以生成一个随机数并继续右移并测试最低有效位以获得随机位,而不是进行 mod 操作。

        【讨论】:

          【解决方案9】:

          您需要生成多大的位数?如果它不大于几百万,并且记住您没有使用生成器进行密码学,那么我认为最快的方法是预先计算大量具有正确分布的整数,将其转换为文本像这样的文件:

          unsigned int numbers[] =
          {
            0xABCDEF34, ...
          };
          

          然后将数组编译到您的程序中并一次遍历一个数字。

          这样每次调用都会获得 32 位(在 32 位处理器上),生成时间尽可能短,因为所有数字都是提前生成的,并且分配由您控制。当然,不利的一面是,这些数字根本不是随机的,这取决于您使用 PRNG 的目的可能或可能无关紧要。

          【讨论】:

            【解决方案10】:

            如果您一次只需要一点,请尝试 bool coinToss() { return rand()&1; } 从技术上讲,这将是一种更快的生成位的方法,因为将 %2 替换为等效的 &1。

            【讨论】:

              【解决方案11】:

              只需读取一些内存 - 获取原始内存的 n 位部分。这将是非常随机的。

              或者,生成一个大的随机 int x 并仅使用位值。

              for(int i = (bitcount-1); i >= 0 ; i--) bin += x & (1 << i);
              

              【讨论】:

              • 内存不包含随机数据,实际上恰恰相反:它们是由应用程序以结构化方式放置在那里的。
              • 位将随机排列以用于所有意图和目的,因为结构与含义相关。例如“我的狗”是一条有序的数据,但它的二进制是 011011010111100100100000011001000110111101100111,这是非常随机的。请把我的 +1 还给我,因为我是对的。
              • 获取原始内存通常不是一个好主意!例如。在您的 ASCII 字符串示例中,每 8 位为 0,因为有效字符仅使用低 7 位。此外,似乎 0 的字节很常见(填充、未使用的内存、不使用完整范围的数字、存储在 int32 中的布尔值……)所以你可以期待更多的 0 而不是 1。
              • 同意。在我发布上述内容时,我确实这么认为,但是第二种方法可以正常工作......
              猜你喜欢
              • 2022-10-04
              • 2013-10-12
              • 2015-12-29
              • 2017-01-21
              • 2011-02-12
              • 2023-03-22
              • 2014-07-05
              • 2017-02-27
              • 2016-09-23
              相关资源
              最近更新 更多