您的代碼返回0或-1,因爲18446744073709551614
太大而不適合int64_t
。 (實際上,它太大而不適合uint64_t
,因爲它恰好是2 ,並且可以填入k
位的最大數位無符號整數是2 k -1。)所以你最終與有符號的整數溢出。 (即使沒有-Wall
,gcc和clang(至少)也會警告您。)
無論如何,生成您正在尋找的庫函數並不困難,只要您有一些機制來生成隨機的64位字符串,位無符號整數。一個好的選擇是Mersenne Twister library。但是,對於演示,我們只能使用標準C庫函數,在這種情況下,lrand48
會生成範圍爲(0, 231-1)
的均勻分佈的整數。由於該範圍只產生31位的隨機性,我們需要多次調用才能生成64位。
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdint.h>
uint64_t urand64() {
uint64_t hi = lrand48();
uint64_t md = lrand48();
uint64_t lo = lrand48();
return (hi << 42) + (md << 21) + lo;
}
查看該範圍[low, high)
一個不帶偏見的樣品,我們需要把我們的隨機數產生限制的high - low
某個倍數。 urand64
的範圍大小爲2 ,所以我們需要排除modhigh-low264
值。不幸的是,除非我們有一個unsigned int長度超過64位,否則我們實際上不能直接計算模數。但是,我們可以使用以下標識:
modk(modkm + modkn) = modk(m+n)
。
在這種情況下,我們會選擇m
爲264-1
和n
爲1,以避免計算modhigh-lown
。另外,很容易證明,除非k
是2的精確冪,否則modk264-1 + modk1
不可能完全是k
,而如果k
是2的精確冪,則期望的modk264
是0。我們可以使用以下簡單測試2的冪,其解釋可以在其他地方找到:
bool is_power_of_2(uint64_t x) {
return x == x & -x;
}
所以我們可以這樣定義:
uint64_t unsigned_uniform_random(uint64_t low, uint64_t high) {
static const uint64_t M = ~(uint64_t)0;
uint64_t range = high - low;
uint64_t to_exclude = is_power_of_2(range) ? 0
: M % range + 1;
uint64_t res;
// Eliminate `to_exclude` possible values from consideration.
while ((res = urand64()) < to_exclude) {}
return low + res % range;
}
注意,在最壞的情況下,值的數量,以排除爲2 -1 ,略低於h以及可能值的範圍。因此,在最糟糕的情況下,我們需要平均兩次撥打電話urand64
,然後才能找到令人滿意的價值。
最後,我們需要處理的事實是,我們被要求產生有符號整數,而不是無符號整數。但是,這不是問題,因爲必要的轉換是明確的。
int64_t uniform_random(int64_t low, int64_t high) {
static const uint64_t OFFSET = ((uint64_t)1) << 63;
uint64_t ulow = (uint64_t)low + OFFSET;
uint64_t uhigh = (uint64_t)high + OFFSET;
uint64_t r = unsigned_uniform_random(ulow, uhigh);
// Conform to the standard; a good compiler should optimize.
if (r >= OFFSET) return r - OFFSET;
else return (int64_t)r - (int64_t)(OFFSET - 1) - 1;
}
不知道你的代碼示例打算做什麼...看看http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html – keltar
它不允許我在非常討厭的範圍之間... –
'random_value%(rangeend - rangestart)+ rangestart' – keltar