[英]how to implement the modulus 2^64 in c for linear congruential generator LCG
這是線性同余生成器的 C 語言實現,具有以下公式:
X_{n+1}=a*X_{n} \\bmod m
下面是線性同余生成器函數的兩個版本,第一個函數生成一個 64 位整數,第二個函數生成一個雙精度數。
下面代碼中的模數是 2^64−1。 我想將模數重寫為 2^64,當我嘗試由於數據類型而出現錯誤時。 由於 2^64 是一個 65 位,並且該函數具有一個“uint64_t”數據類型,它包含 64 位。 我尋找解決方案來解決這個問題,比如使用 128 位數據類型,但我在 Mac 上使用 Xcode 並且它不支持它,有些人建議使用 GPM,但我不喜歡它。 我想過將 Modulus 存儲在一個數組中,但我不知道以后如何才能使最終輸出成為 64 位整數。
有什么簡單的方法可以做到嗎? 因為我需要第一個函數的最終輸出是一個 64 位整數,而第二個函數的輸出是一個雙精度數,所以稍后我可以在進一步的計算中使用它們。
編輯:在代碼中,模數的值為 m=18446744073709551615,即 2^64−1。 我想將其更改為 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;
}
第二個具有雙精度的函數:
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;
}
這些函數中使用的模數不是$2^{64}-1$而是$2^{64}$ 。
如果$x$是 2 的冪,您總是可以將模$x$除以:
s = s*a & (x-1);
這就是這里所做的。
無論如何,此操作在這里是多余的,因為通過切斷 128 位長結果的較高 64 位,乘法的結果會自動截斷為 64 位。 簡化版:
uint64_t linear_congruential()
{
static uint64_t s= 1442695040888963407; // seed
const uint64_t a = 6364136223846793005; // the multiplier a
s *= a;
return s;
}
第二個功能將不起作用。 由於 s 和 m 是整數,因此 s/m 將作為整數除法進行,即結果將向下舍入到下一個整數。 它將(幾乎)始終為 0。相反,您應該這樣寫:
q = s / (double)m;
編輯:變量 s 必須是靜態的。 它必須為下一次調用該函數保留其值。
順便說一句,將 64 位無符號整數轉換為雙精度數時,標准方法是:
unsigned long long my_big_number = .....;
double my_double_number = my_big_number / (double)MAX_UINT;
但這可能更快:
double my_double_number = ( static_cast<double>(my_big_number>>2) / 2.0);
這利用了 IEEE 雙精度位格式,如果您的整數是全范圍 64 位,那么雙精度數將在[ 0.0 .. 2.0 )
范圍內。 最后除以 2.0 使其成為目標范圍[ 0.0 .. 1.0 )
將比除以(double)MAX_INT
更快。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.