C 如何基于字节数组生成随机数?
假设我有一个来自安全PRNG的字节数组,并且我需要使用该数据生成一个介于1和10之间的数字,我该如何正确地做到这一点?根据后续评论,您需要的似乎是[C 如何基于字节数组生成随机数?,c,random,cryptography,prng,C,Random,Cryptography,Prng,假设我有一个来自安全PRNG的字节数组,并且我需要使用该数据生成一个介于1和10之间的数字,我该如何正确地做到这一点?根据后续评论,您需要的似乎是[%] 您可能还需要检查相关的 注意:每次我们对一个随机数使用模运算符时,都有可能会遇到这样的情况,最终导致随机数的公平分布不平衡。你必须处理好这件事 有关这方面的详细讨论,请参阅此内容和相关答案。这取决于一系列因素。安全PRNG有时生成长字节数组而不是整数,假设它是16字节长的数组,然后提取32位整数,如下所示:buf[0]*0x1000000+bu
%
]
您可能还需要检查相关的
注意:每次我们对一个随机数使用模运算符时,都有可能会遇到这样的情况,最终导致随机数的公平分布不平衡。你必须处理好这件事
有关这方面的详细讨论,请参阅此内容和相关答案。这取决于一系列因素。安全PRNG有时生成长字节数组而不是整数,假设它是16字节长的数组,然后提取32位整数,如下所示:
buf[0]*0x1000000+buf[1]*0x10000+buf[2]*0x100+buf[3]
或使用移位运算符。这是随机的,所以大端点/小端点无关紧要
char randbytes[16];
//...
const char *p = randbytes;
//assumes size of int is 4
unsigned int rand1 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand2 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand3 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3]; p += 4;
unsigned int rand4 = p[0] << 24 + p[1] << 16 + p[2] << 8 + p[3];
charrandbytes[16];
//...
const char*p=randbytes;
//假设int的大小为4
unsigned int rand1=p[0]OK,所以在我使用Eclipse C/C++IDE之前,这个答案是用Java编写的:
public final static int simpleBound(Random rbg, int n) {
final int BYTE_VALUES = 256;
// sanity check, only return positive numbers
if (n <= 0) {
throw new IllegalArgumentException("Oops");
}
// sanity check: choice of value 0 or 0...
if (n == 1) {
return 0;
}
// sanity check: does not fit in byte
if (n > BYTE_VALUES) {
throw new IllegalArgumentException("Oops");
}
// optimization for n = 2^y
if (Integer.bitCount(n) == 1) {
final int mask = n - 1;
return retrieveRandomByte(rbg) & mask;
}
// you can skip to this if you are sure n = 10
// z is upper bound, and contains floor(z / n) blocks of n values
final int z = (BYTE_VALUES / n) * n;
int x;
do {
x = retrieveRandomByte(rbg);
} while (x >= z);
return x % n;
}
public final static int simpleBound(随机rbg,int n){
最终整数字节_值=256;
//健全性检查,仅返回正数
if(n字节_值){
抛出新的IllegalArgumentException(“Oops”);
}
//n=2^y的优化
if(整数位计数(n)==1){
最终整数掩码=n-1;
返回检索字节(rbg)和掩码;
}
//如果确定n=10,则可以跳过此步骤
//z是上限,包含n个值的楼层(z/n)块
最终整数z=(字节_值/n)*n;
int x;
做{
x=检索数和单位(rbg);
}而(x>=z);
返回x%n;
}
因此,n是范围[0..n]中的最大值,即n是互斥的。对于范围[1..10],只需将结果增加1即可。将数组视为一个大的无符号整数。答案很简单:
(Big_Number % 10) + 1
因此,所需要的只是一种求大整数模10的方法。使用:
请不要误会我的意思,但答案是写一段代码。
:-)顺便说一句,你在找吗?@SouravGhosh是的,可以用模数来做,如果你的评论是我接受的答案。如果你选择%
,那么你可能还想读一读关于这个问题。我个人会查找一段代码(通常称为getInt(intmax)
)并将其整合。否则很容易产生偏差。相关。请注意备注。请添加一些关于偏差的信息,以使此答案完整。@MaartenBodewes已更新。请查看。更好。不幸的是,链接中的答案非常差。也许可以改为尝试。当然,您可以使用8位数字表示范围0..10-depends,如果您希望更改为更大的范围,以及希望从随机池中提取多少数据(您只需要4位就可以了,但16次中有6次拒绝,这相当糟糕)。请注意,您最多需要24个字节才能生成1到10之间的数(在此之后,不生成1到10之间的数字的可能性变得小于1/2^128:P)请注意,如果要降低所需的最大字节数(在本例中为20个字节),建议使用16位数字。我不知道如何翻译(Integer.bitCount(n)==1)到C,所以我不能使用这个函数。你可以简单地省略它,这只是优化所必需的。但是,。如果你需要一个关于如何将无符号字符
转换为32位值的链接,只需尖叫:)这将给你留下一个小但可检测的偏差,为什么你需要16个字节来生成一个32位的整数???。这是从16个字节中提取的4个不同的整数,这是安全PRNG的典型输出。我在键入后改变了主意,我认为这个问题与安全无关PRNG@Maarten给定OP的Bodewes正在使用“secure PRNG”,当然长度合理,所以我同意,实际上不需要考虑偏差问题。我想使用此代码,但实际上我不需要在1和10之间进行选择,它需要变量。我可以安全地用上限/下限变量替换代码中出现的每一个1和10吗?@Muis几乎。LetArrayModX()
返回范围[0…X-1],然后用X=upper-lower+1
添加下限。如果数字超出范围255,请使用比无符号字符*a
更大的对象,如uint32\u t*a
,然后可以替换“10”。如果“10”大于INT\u MAX
,则会出现一些额外的问题。IOWs“带有上限/下限变量的代码”太模糊。最好说数字的类型或范围,如:0此答案仍然有偏差,实际上不需要偏差。@Maarten BodewesArraymod10偏差检测()
检测并报告二进制数上模10
出现的偏差。是否指其他偏差?
#include <limits.h>
#include <stdlib.h>
int ArrayMod10(const unsigned char *a, size_t n) {
int mod10 = 0;
int base = (UCHAR_MAX + 1) % 10;
for (size_t i = n; i-- > 0; ) {
mod10 = (base*mod10 + a[i]) % 10;
base = (base * base) % 10;
}
return mod10;
}
void test10(size_t n) {
unsigned char a[n];
// fill array with your secure PRNG
for (size_t i = 0; i<n; i++) a[i] = rand();
return ArrayMod10(a, n) + 1;
}
int ArrayMod10BiasDetect(const unsigned char *a, size_t n, bool *biasptr) {
bool bias = true;
int mod10 = 0;
int base = (UCHAR_MAX + 1) % 10; // Note base is usually 6: 256%10, 65536%10, etc.
for (size_t i = n; i-- > 0; ) {
mod10 = (base*mod10 + a[i]) % 10;
if (n > 0) {
if (a[i] < UCHAR_MAX) bias = false;
} else {
if (a[i] < UCHAR_MAX + 1 - base) bias = false;
}
base = (base * base) % 10;
}
*biaseptr = bias;
return mod10;
}