C XorShift32是如何工作的?

C XorShift32是如何工作的?,c,static,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;

我有一个家庭作业,我需要实现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;
}
uint32\u t异或移位32(uint32\u t状态[静态1])
{
uint32_t x=状态[0];
x^=x>17;

维基百科文章中的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));
  }
}
#包括
#包括
/*状态字必须初始化为非零*/
uint32\u t异或移位32(uint32\u t状态[])
{
/*Marsaglia第4页的“xor”算法,“Xorshift RNGs”*/
uint32_t x=状态[0];
x^=x>17;
x^=x 7;

这是对美好事物的延伸评论

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

Xorshift伪随机数生成器系列的作者,也开发了一套称为的统计工具,可用于分析生成序列的“随机性”。目前,这些测试可能是最广泛使用和最可信的;特别是160测试集

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

我自己最喜欢的PRNG是Xorshift64*,它的周期为264-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);
}
使用高位;序列的高位32位确实通过了TestU01套件中的所有BigCrunch测试,因此这是一个非常好的(随机性和效率)双精度均匀随机数生成器——我的典型用例

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

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

大多数C标准库实现中的
rand()
函数都是a函数。它们经常会遇到系数选择不当的问题,现在也会遇到模运算符相对缓慢的问题(当模不是二的幂时)

最广泛使用的伪随机数发生器是由Makoto Matsumoto设计的(松本 眞) 和西村拓治(西村 拓士). 它是一个扭曲的广义线性反馈移位寄存器,具有相当大的状态(约2500字节)和非常长的周期(219937-1)


当我们谈论真正的随机数生成器时,我们通常指的是伪随机数生成器(通常是加密安全的生成器)和至少具有某种真正物理随机性的随机位源的组合

至少在Linux、Mac OS和BSD中,操作系统内核公开了伪随机数的来源(在Linux和OpenBSD中,在Linux中,
/dev/urandom
/dev/arandom
/dev/random
在许多Unix中,等等)。熵是从物理电子源收集的,如内部处理器延迟、物理中断线计时、(旋转磁盘)硬盘驱动器计时,甚至可能是键盘和鼠标。许多主板和一些处理器甚至具有可用作熵源(甚至直接用作“可信随机性源”)的信息

^
在C中)用于将随机性混合到生成器状态。这是有效的,因为已知位和随机位之间的异或会产生随机位;异或保留随机性。混合熵池时(位状态中具有一定程度的随机性)使用XOR,结果将至少具有与源相同的熵

请注意,这并不意味着您可以通过混合两个或多个生成器的输出来获得“更好”的随机数。真正随机性的统计数据对于人类来说是难以理解的(只需看看早期常见的
rand()
实现有多差!可怕!)。最好选择一个生成器(或在编译时或运行时切换的一组生成器)它通过了BigCrunch测试,并确保在每次运行时都有一个良好的随机初始状态。这样,您就可以利用许多数学家和其他几十年来从事这些工作的人的工作,并可以专注于其他方面,即您自己擅长的方面。

您甚至可以编译该函数吗?它不符合标准C(关于函数参数),因此如果您的编译器接受它,那么一些语言扩展正在发挥作用。您需要检查您的实现文档(或者您的类注释)以了解它的含义。另一方面,可能只是输入错误
static inline double prng_one(prng_state *p)
{
    return prng_u64(p) / 18446744073709551616.0;
}