XorShift32如何工作?

时间:2018-12-21 14:06:10

标签: c static

我有这个作业需要实现xorshift32(我不能使用其他任何东西),因此我可以生成一些数字,但我不了解该算法的工作方式或实现方式。

我正在尝试打印生成的数字,但是由于state [static 1]参数,我不知道如何调用xorshift32函数。

uint32_t xorshift32(uint32_t state[static 1])
{
    uint32_t x = state[0];
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    state[0] = x;
    return x;
}

除了Wikipedia(en.wikipedia.org/wiki/Xorshift)上的内容外,我对xorshft32的了解不多。

2 个答案:

答案 0 :(得分:1)

这是对好的answer by Jabberwocky的扩展注释。

Xorshift变体rand()和基本上所有随机数生成器函数实际上都是pseudorandom number generators。它们不是“真正的随机数”,因为它们生成的数字顺序取决于其内部状态。但它们是"pseudorandom",因为如果您不知道生成器的内部状态,则它们生成的数字序列在统计意义上是随机的。

George Marsaglia是Xorshift家族伪随机数生成器的作者,他还开发了一套称为Diehard tests的统计工具,可用于分析所生成序列的“随机性”。当前,TestU01测试可能是使用最广泛且最受信任的测试。特别是160次测试的BigCrush集。

由普通的伪随机数生成器生成的序列通常允许人们确定生成器的内部状态。这意味着观察足够长的生成序列,可以相当可靠地预测未来的序列。 Cryptographically secure pseudorandom number generators通常通过对输出应用加密安全的哈希函数来避免这种情况;一个人需要一个完整序列的目录才能跟随它。当周期长于2 256 左右时,整个可观测宇宙中的重子物质不足以存储序列。

我最喜欢的PRNG是Xorshift64 *,其周期为2 64 -1,并且通过了BigCrush中MatrixRank的所有测试。在C99及更高版本中,您可以使用

#include <inttypes.h>

typedef struct {
    uint64_t  state;
} prng_state;

static inline uint64_t prng_u64(prng_state *const p)
{
    uint64_t  state = p->state;
    state ^= state >> 12;
    state ^= state << 25;
    state ^= state >> 27;
    p->state = state;
    return state * UINT64_C(2685821657736338717);
}

状态可以初始化为任何非零的uint64_t。 (零状态将导致生成器生成所有零,直到无穷大。周期为2 64 -1,因为生成器在每个周期内将完全具有一次每个64位状态(不包括零)。 )

对于大多数用例来说已经足够好了,而且速度非常快。它属于linear-feedback shift register个伪随机数生成器的类别。

请注意,该变体返回介于0和1之间的均匀分布。

static inline double prng_one(prng_state *p)
{
    return prng_u64(p) / 18446744073709551616.0;
}

使用高位;该序列的高32位确实通过了TestU01套件中的所有BigCrunch测试,因此对于双精度统一随机数来说,这是一个出乎意料的好(随机性和效率)生成器-我的典型用例。

通过将生成器状态指定为参数,上述格式允许在单个进程中使用多个独立的生成器。如果基本生成器是在头文件中实现的(因此static inline;它是预处理程序,类似于宏),则可以通过在头文件之间切换并重新编译二进制文件来在生成器之间切换。

(通常情况下,最好使用单个生成器,除非您在伪随机数繁重的模拟器中使用多个线程,否则在这种情况下为每个线程使用单独的生成器将有很大帮助;避免了线程之间的缓存行乒乓竞争尤其是发电机状态。)

大多数C标准库实现中的rand()函数是linear-congruential generator。他们经常遭受系数选择不当的困扰,如今,还受到模运算符相对较慢的影响(当模数不是2的幂时)。

使用最广泛的伪随机数生成器是Mersenne Twister,由松本诚(Makoto Matsumoto)和西村拓士(Takuji Nishimura)共同开发。它是一个扭曲的广义线性反馈移位寄存器,具有很大的状态(大约2500个字节)和很长的周期(2 19937 -1)。


当我们提到 true 随机数生成器时,通常是指伪随机数生成器(通常是加密安全的生成器)和entropy的来源的组合;具有一定程度的真实物理随机性的随机位。

至少在Linux,Mac OS和BSD中,操作系统内核公开伪随机数源(在Linux和OpenBSD中为getentropy(),在Linux中为/dev/urandom,{ {1}},/dev/arandom(在许多Unix中,依此类推)。熵是从物理电子源收集的,例如内部处理器等待时间,物理中断线时序,(磁盘)硬盘驱动器时序,甚至可能是键盘和鼠标。许多主板和某些处理器甚至都具有getrandom(),它们可以用作熵的来源(甚至可以直接用作“可信随机性来源”)。

hardware random number sources(C中的/dev/random)用于随机混合到生成器状态。这是可行的,因为已知位与随机位之间的异或结果将导致随机位; XOR保留随机性。当使用XOR混合熵池(在位状态中具有一定程度的随机性)时,结果的熵至少与源的熵相同。

请注意,不是并不表示您通过混合两个或多个生成器的输出来获得“更好的”随机数。真正的随机性统计数据让人难以理解(只需看看常见的早期^实现有多糟糕!太可怕了!)。最好选择一个通过BigCrunch测试的生成器(或在生成时或运行时在生成器之间切换),并确保它在每次运行时都具有良好的随机初始状态。这样,您就可以利用许多数学家和其他从事数十年研究的人的工作,并且可以专注于自己擅长的其他事情。

答案 1 :(得分:0)

维基百科文章中的C代码有些令人误解:

这是一个同时使用32位和64位版本的工作示例:

#include <stdio.h>
#include <stdint.h>

/* The state word must be initialized to non-zero */
uint32_t xorshift32(uint32_t state[])
{
  /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
  uint32_t x = state[0];
  x ^= x << 13;
  x ^= x >> 17;
  x ^= x << 5;
  state[0] = x;
  return x;
}

uint64_t xorshift64(uint64_t state[])
{
  uint64_t x = state[0];
  x ^= x << 13;
  x ^= x >> 7;
  x ^= x << 17;
  state[0] = x;
  return x;
}

int main()
{
  uint32_t state[1] = {1234};  // "seed" (can be anthing but 0)

  for (int i = 0; i < 50; i++)
  {
    printf("%u\n", xorshift32(state));
  }

  uint64_t state64[1] = { 1234 };  // "seed" (can be anthing but 0)

  for (int i = 0; i < 50; i++)
  {
    printf("%llu\n", xorshift64(state64));
  }
}

在Wikipedia文章及其脚注中解释了数学方面。

其余是C语言的基本知识,^是C位XOR运算符。