简体   繁体   English

如何在 c 中为线性同余生成器 LCG 实现模数 2^64

[英]how to implement the modulus 2^64 in c for linear congruential generator LCG

This is an implementation in C for linear congruential generator that has this formula:这是线性同余生成器的 C 语言实现,具有以下公式:

X_{n+1}=a*X_{n} \\bmod m X_{n+1}=a*X_{n} \\bmod m

Below are two versions of the linear congruential generator function, the first function generates a 64-bit integer number and the second one should generate a double.下面是线性同余生成器函数的两个版本,第一个函数生成一个 64 位整数,第二个函数生成一个双精度数。

The Modulus in the codes below is 2ˆ64−1.下面代码中的模数是 2^64−1。 I want to rewrite the modulus to be 2^64, when I tried that I get an error because of the data type.我想将模数重写为 2^64,当我尝试由于数据类型而出现错误时。 Since 2^64 is a 65 bit and the function has a "uint64_t" data type that holds 64 bits.由于 2^64 是一个 65 位,并且该函数具有一个“uint64_t”数据类型,它包含 64 位。 I looked for solutions to solve the problem like using a 128 bits data type but I am using Xcode on Mac and it does not support it, and some recommend using GPM but I don't prefer it.我寻找解决方案来解决这个问题,比如使用 128 位数据类型,但我在 Mac 上使用 Xcode 并且它不支持它,有些人建议使用 GPM,但我不喜欢它。 I thought about storing the Modulus in an array but I don't know how I can later get the final output to be a 64-bit integer.我想过将 Modulus 存储在一个数组中,但我不知道以后如何才能使最终输出成为 64 位整数。

Is there any simple way to do it?有什么简单的方法可以做到吗? because I need the final output from the first function to be a 64-bit integer and the output from the second function to be a double, so later I can use them in further calculations.因为我需要第一个函数的最终输出是一个 64 位整数,而第二个函数的输出是一个双精度数,所以稍后我可以在进一步的计算中使用它们。

EDIT: In the code the modulus has the value m= 18446744073709551615 that is 2ˆ64−1.编辑:在代码中,模数的值为 m=18446744073709551615,即 2^64−1。 I want to change that to be m= 18446744073709551616 that is 2^64.我想将其更改为 m= 18446744073709551616,即 2^64。 I get an error when I do that because of the data type.由于数据类型,当我这样做时出现错误。 How I can change the modulus to be m= 18446744073709551616 = 2^64?如何将模数更改为 m= 18446744073709551616 = 2^64?

uint64_t linear_congruential()
   {
    uint64_t s= 1442695040888963407;// seed
    unsigned long long int m=18446744073709551615; // The Modulus 2ˆ64−1    
    uint64_t a=6364136223846793005; // the multiplier a
    s=(s * a )&m;
    return s;
    }

The second function that has double:第二个具有双精度的函数:

double linear_congruential_d()
 {
  double q;
  uint64_t s= 1442695040888963407; //seed
  unsigned long long int m=18446744073709551615; // The Modulus 2ˆ64−1
  uint64_t a=6364136223846793005 ; // the multiplier a
  s=(s * a )&m;
  q=s/m; 
  return q;
 }

The modulus used in these functions is not $2^{64}-1$ but $2^{64}$ .这些函数中使用的模数不是$2^{64}-1$而是$2^{64}$
If $x$ is a power of 2, you can always divide modulo $x$ by:如果$x$是 2 的幂,您总是可以将模$x$除以:

s = s*a & (x-1);

That is what is done here.这就是这里所做的。

This operation is superfluous anyways here, since the result of the multiply is automatically truncated to 64 bit by cutting off the higher 64 bit of the 128 bit long result.无论如何,此操作在这里是多余的,因为通过切断 128 位长结果的较高 64 位,乘法的结果会自动截断为 64 位。 Simplified version:简化版:

uint64_t linear_congruential()
{
    static uint64_t s= 1442695040888963407; // seed
    const uint64_t a = 6364136223846793005; // the multiplier a
    s *= a;
    return s;
}

The second function will not work.第二个功能将不起作用。 As s and m are integer, s/m will be done as integer division, that is, the result will be rounded down to the next integer.由于 s 和 m 是整数,因此 s/m 将作为整数除法进行,即结果将向下舍入到下一个整数。 It will be (almost) always 0. Instead you should write:它将(几乎)始终为 0。相反,您应该这样写:

q = s / (double)m;

Edit: the variable s must be made static.编辑:变量 s 必须是静态的。 It has to keep its value for the next call to the function.它必须为下一次调用该函数保留其值。

Just an aside, when converting a 64-bit unsigned integer into a double, the standard way is this:顺便说一句,将 64 位无符号整数转换为双精度数时,标准方法是:

unsigned long long my_big_number = .....;
double my_double_number = my_big_number / (double)MAX_UINT;

But this may be faster:但这可能更快:

double my_double_number = ( static_cast<double>(my_big_number>>2) / 2.0);

That takes advantage of the IEEE double precision bit format and, if your integer is full range 64-bits, then the double will be in the range [ 0.0 .. 2.0 ) .这利用了 IEEE 双精度位格式,如果您的整数是全范围 64 位,那么双精度数将在[ 0.0 .. 2.0 )范围内。 The final dividing by 2.0 to put it the target range of [ 0.0 .. 1.0 ) will be faster than dividing by (double)MAX_INT .最后除以 2.0 使其成为目标范围[ 0.0 .. 1.0 )将比除以(double)MAX_INT更快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM