在 C 中生成随机 64/32/16/ 和 8 位整数

Generating random 64/32/16/ and 8-bit integers in C

我希望有人能让我理解为什么代码会这样工作。我正在努力解决问题,但迷路了。

我的教授给了我们这个代码片段,我们必须使用它来在 C 中生成随机数。有问题的片段生成一个 64 位整数,我们必须对其进行调整以生成 32 位整数、16 位和 8 位整数。我完全不知道从哪里开始,我不一定要寻求解决方案,只是寻求原始代码段的工作原理,以便我可以从那里进行调整。

long long rand64()
{
 int a, b;
 long long r;
 a = rand();
 b = rand();
 r = (long long)a;
 r = (r << 31) | b;
 return r;
}

我对这段代码的疑问是:

  1. 为什么要移31位?我以为 rand() 生成了一个 0-32767 之间的数字,它是 16 位,那不是 48 位吗?
  2. 我们为什么说| (或)b 在倒数第二行?

我做一个相对安全的假设,即在您计算机的 C 实现中,long long 是 64 位数据类型。

这里的关键是,由于 long long r 是有符号的,任何设置了最高位的值都将为负数。因此,代码将 r 移动 31 位以避免设置该位。

| 是一个逻辑位运算符,它通过设置 r 中的所有位来组合两个值,这些位在 b 中设置。

编辑:

看了一些评论后,我意识到我的回答需要更正。 rand() returns 不超过 RAND_MAX 的值,通常为 2^31-1。因此,r 是一个 31 位整数。如果将其向左移动 32 位,则可以保证其第 31 位(从 0 开始计数)始终为零。

rand() 生成一个随机值 [0...RAND_MAX] 的声誉有问题 - 但让我们把这个声誉放在一边并假设 rand() 足够好并且它是一个 Mersenne number (power-of-2 - 1).

OP 代码的弱点:如果 RAND_MAX == pow(2,31)-1 很常见,那么 OP 的 rand64() 仅 returns 值 [0...pow(2,62))。


相反,根据需要循环多次。

要找出每次调用返回多少个随机位,我们需要 log2(RAND_MAX + 1)。幸运的是,使用来自 Is there any way to compute the width of an integer type at compile-time?

awesome 宏很容易
#include <stdlib.h>
/* Number of bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 2040 */
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define RAND_MAX_BITWIDTH (IMAX_BITS(RAND_MAX))

示例:rand_ul() returns [0...ULONG_MAX] 范围内的随机值,可以是 unsigned long 32 位、64 位等

unsigned long rand_ul(void) {
  unsigned long r = 0;
  for (int i=0; i<IMAX_BITS(ULONG_MAX); i += RAND_MAX_BITWIDTH) {
    r <<= RAND_MAX_BITWIDTH;
    r |= rand();
  }
  return r;
}