在 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;
}
我对这段代码的疑问是:
- 为什么要移31位?我以为 rand() 生成了一个 0-32767 之间的数字,它是 16 位,那不是 48 位吗?
- 我们为什么说| (或)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;
}
我希望有人能让我理解为什么代码会这样工作。我正在努力解决问题,但迷路了。
我的教授给了我们这个代码片段,我们必须使用它来在 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;
}
我对这段代码的疑问是:
- 为什么要移31位?我以为 rand() 生成了一个 0-32767 之间的数字,它是 16 位,那不是 48 位吗?
- 我们为什么说| (或)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?
#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;
}