Sue*_*Sue 6 c random primes modular-arithmetic
我正在尝试用Mersenne prime(2 31 -1)作为模数来实现随机数生成器.以下工作代码基于几个相关的帖子:
然而,
它不起作用uint32_t hi, lo;,这意味着我不理解问题的签名与未签名方面.
基于上面的#2,我期待答案是(hi + lo).这意味着,我不明白为什么需要以下声明.
if (x1 > r)
x1 += r + 2;
Run Code Online (Sandbox Code Playgroud)
有人可以澄清我的困惑的来源吗?
代码本身可以改进吗?
发电机应该避免0或2 31 -1作为种子吗?
如何为一个素数(2 p -k)改变代码?
#include <inttypes.h>
// x1 = a*x0 (mod 2^31-1)
int32_t lgc_m(int32_t a, int32_t x)
{
printf("x %"PRId32"\n", x);
if (x == 2147483647){
printf("x1 %"PRId64"\n", 0);
return (0);
}
uint64_t c, r = 1;
c = (uint64_t)a * (uint64_t)x;
if (c < 2147483647){
printf("x1 %"PRId64"\n", c);
return (c);
}
int32_t hi=0, lo=0;
int i, p = 31;//2^31-1
for (i = 1; i < p; ++i){
r |= 1 << i;
}
lo = (c & r) ;
hi = (c & ~r) >> p;
uint64_t x1 = (uint64_t ) (hi + lo);
// NOT SURE ABOUT THE NEXT STATEMENT
if (x1 > r)
x1 += r + 2;
printf("c %"PRId64"\n", c);
printf("r %"PRId64"\n", r);
printf("\tlo %"PRId32"\n", lo);
printf("\thi %"PRId32"\n", hi);
printf("x1 %"PRId64"\n", x1);
printf("\n" );
return((int32_t) x1);
}
int main(void)
{
int32_t r;
r = lgc_m(1583458089, 1);
r = lgc_m(1583458089, 2000000000);
r = lgc_m(1583458089, 2147483646);
r = lgc_m(1583458089, 2147483647);
return(0);
}
Run Code Online (Sandbox Code Playgroud)
下面的if语句
if (x1 > r)
x1 += r + 2;
Run Code Online (Sandbox Code Playgroud)
应该写成
if (x1 > r)
x1 -= r;
Run Code Online (Sandbox Code Playgroud)
两个结果都以 2^31 为模:
x1 + r + 2 = x1 + 2^31 - 1 + 2 = x1 + 2^31 + 1
x1 - r = x1 - (2^31 - 1) = x1 - 2^31 + 1
Run Code Online (Sandbox Code Playgroud)
第一个解决方案溢出 anint32_t并假设从uint64_t到的转换int32_t是模 2^31。虽然许多 C 编译器以这种方式处理转换,但这并不是 C 标准所强制的。实际结果是实现定义的。
第二种解决方案避免溢出并适用于int32_t和uint32_t。
您还可以使用整数常量r:
uint64_t r = 0x7FFFFFFF; // 2^31 - 1
Run Code Online (Sandbox Code Playgroud)
或者简单地
uint64_t r = INT32_MAX;
Run Code Online (Sandbox Code Playgroud)
编辑:对于 2^pk 形式的素数,您必须使用带有 p 位的掩码并使用以下命令计算结果
uint32_t x1 = (k * hi + lo) % ((1 << p) - k)
Run Code Online (Sandbox Code Playgroud)
如果k * hi + lo可以溢出 a uint32_t(即(k + 1) * (2^p - 1) >= 2^32),则必须使用 64 位算术:
uint32_t x1 = ((uint64_t)a * x) % ((1 << p) - k)
Run Code Online (Sandbox Code Playgroud)
根据平台的不同,后者可能会更快。