簡體   English   中英

如何從 rand() 獲取特定范圍的數字?

[英]How do I get a specific range of numbers from rand()?

srand(time(null));

printf("%d", rand());

給出了一個高范圍的隨機數(0-32000ish),但我只需要大約 0-63 或 0-127,雖然我不確定如何 go 關於它。 有什么幫助嗎?

rand() % (max_number + 1 - minimum_number) + minimum_number

因此,對於0-65:

rand() % (65 + 1 - 0) + 0

(顯然,您可以將0保留為零,但這是完整的)。

請注意,這將使隨機性稍有偏差,但如果您未執行特別敏感的操作,則可能無需擔心。

在這里檢查

http://c-faq.com/lib/randrange.html

對於這些技術中的任何一種,如有必要,都可以直接改變范圍。 [M,N]范圍內的數字可以用類似

M + rand() / (RAND_MAX / (N - M + 1) + 1)

您可以使用此:

int random(int min, int max){
   return min + rand() / (RAND_MAX / (max - min + 1) + 1);
}

來自:

comp.lang.c常見問題清單·問題13.16

問:如何獲得一定范圍內的隨機整數?

答:顯而易見的方法

 rand() % N /* POOR */ 

(試圖將數字從0返回到N-1)的效果很差,因為許多隨機數生成器的低階位令人痛苦地是非隨機​​的。 (請參閱問題13.18 。)更好的方法是:

 (int)((double)rand() / ((double)RAND_MAX + 1) * N) 

如果您不想使用浮點數,則另一種方法是

 rand() / (RAND_MAX / N + 1) 

如果您只需要以1 / N的概率做某事,則可以使用

 if(rand() < (RAND_MAX+1u) / N) 

所有這些方法顯然都需要了解RAND_MAX(ANSI#在<stdlib.h>中定義),並假定N比RAND_MAX小得多。 當N接近RAND_MAX時,並且如果隨機數生成器的范圍不是N的倍數(即(RAND_MAX + 1)%N!= 0),則所有這些方法都將失效:某些輸出比其他。 (使用浮點數無濟於事;問題在於rand返回RAND_MAX + 1個不同的值,這些值不能總是均勻地分成N個存儲桶。)如果這是一個問題,那么您唯一可以做的就是調用rand多個次,丟棄某些值:

 unsigned int x = (RAND_MAX + 1u) / N; unsigned int y = x * N; unsigned int r; do { r = rand(); } while(r >= y); return r / x; 

對於這些技術中的任何一種,如有必要,都可以直接改變范圍。 [M,N]范圍內的數字可以用類似

 M + rand() / (RAND_MAX / (N - M + 1) + 1) 

(請注意,順便說一下,R​​AND_MAX是一個常量,它告訴您C庫rand函數的固定范圍是什么。您不能將RAND_MAX設置為其他某個值,也無法請求rand返回數字在其他范圍內)

如果您從隨機數生成器開始,該生成器返回0到1之間的浮點值(例如,在問題13.15中暗示的PMrand的最新版本,或者在問題13.21中暗示了drand48),那么您要做的所有操作都可以從中獲取整數0到N-1是該發生器的輸出乘以N:

 (int)(drand48() * N) 

其他連結

參考:K&R2第2節。 7.8.7羽 168
PCS秒 11頁 172

引用自: http : //c-faq.com/lib/randrange.html

正如其他海報所斷言的那樣,對結果取模,將為您提供幾乎隨機的東西,但並非完全如此。

考慮這個極端的例子,假設您要模擬拋硬幣,返回0或1。您可以這樣做:

isHeads = ( rand() % 2 ) == 1;

看起來無害,對嗎? 假設RAND_MAX只有3。當然要高得多,但這里的要點是,當使用不均勻划分RAND_MAX的模數時會有偏差。 如果您想要高質量的隨機數,將會遇到問題。

考慮我的例子。 可能的結果是:

rand()  freq. rand() % 2
0       1/3   0
1       1/3   1
2       1/3   0

因此,“尾巴”的發生頻率是“頭”的兩倍!

阿特伍德先生在《編碼恐怖》中討論了此事

正如其他人指出的那樣,簡單地使用模數會使單個數字的概率偏斜,因此較小的數字是首選。

Java的java.util.Random類使用了一種非常巧妙且很好的解決方案:

public int nextInt(int n) {
    if (n <= 0)
        throw new IllegalArgumentException("n must be positive");

    if ((n & -n) == n)  // i.e., n is a power of 2
        return (int)((n * (long)next(31)) >> 31);

    int bits, val;
    do {
        bits = next(31);
        val = bits % n;
    } while (bits - val + (n-1) < 0);
    return val;
}

我花了一些時間來理解它為什么起作用,我把它留給讀者作為練習,但這是一個非常簡潔的解決方案,它將確保數字具有相等的概率。

該代碼段中的重要部分是while循環的條件,該條件將拒絕落入數字范圍內的數字,否則將導致分布不均。

更新為不使用#define

double RAND(double min, double max)
{
    return (double)rand()/(double)RAND_MAX * (max - min) + min;
}
double scale = 1.0 / ((double) RAND_MAX + 1.0);
int min, max;
...
rval = (int)(rand() * scale * (max - min + 1) + min);

如果您不太在意低階位的“隨機性”,則只需rand()%HI_VAL。

也:

(double)rand() / (double)RAND_MAX;  // lazy way to get [0.0, 1.0)

天真的方法是:

int myRand = rand() % 66; // for 0-65

這可能是一個非常不均勻的分布(取決於您的最大值),但是非常接近。

為了解釋為什么它不太統一,請考慮以下非常簡單的示例:
假設RAND_MAX為4,並且您想要一個0-2之間的數字。 下表顯示了可能獲得的值:

rand()   |  rand() % 3
---------+------------
0        |  0
1        |  1
2        |  2
3        |  0

看到問題了嗎? 如果最大值不是RAND_MAX的偶數除數,則您更有可能選擇較小的值。 但是,由於RAND_MAX通常為32767,因此偏差可能足夠小,無法在大多數情況下使用。

有多種方法可以解決此問題。 有關Java的Random如何處理的說明,請參見此處

rand()將返回介於0和RAND_MAX之間的數字,該數字至少為32767。

如果要獲取一個范圍內的數字,則可以使用模數。

int value = rand() % 66; // 0-65

要獲得更高的准確性, 請查看本文 它討論了為什么模數不一定是好的(分布不好,尤其是在高端),並提供了多種選擇。

這個答案不關注隨機性,而是算術順序。 為了獲得一個范圍內的數字,通常我們可以這樣:

// the range is between [aMin, aMax]
double f = (double)rand() / RAND_MAX;
double result = aMin + f * (aMax - aMin);

但是,有可能(aMax-aMin)溢出。 例如aMax = 1,aMin = -DBL_MAX。 一種更安全的方法是這樣寫:

// the range is between [aMin, aMax]
double f = (double)rand() / RAND_MAX;
double result = aMin - f * aMin + f * aMax;

基於此概念,可能會引起問題。

rand() % (max_number + 1 - minimum_number) + minimum_number
// 1. max_number + 1 might overflow
// 2. max_number + 1 - min_number might overflow

我認為以下做法是正確的。 自從接觸C以來已經有一段時間了。想法是使用除法,因為模數並不總是給出隨機結果。 我將1加到RAND_MAX,因為有很多可能的值都來自rand,包括0。而且由於范圍也是0(含0),所以我也加了1。 我認為數學安排正確,可以避免整數數學問題。

#define MK_DIVISOR(max) ((int)((unsigned int)RAND_MAX+1/(max+1)))

num = rand()/MK_DIVISOR(65);

如果您關心隨機數的質量,請不要使用rand()

使用其他一些prng,例如http://en.wikipedia.org/wiki/Mersenne_twister或其他高質量的prng之一

然后就去模數

只是為現有答案添加一些額外的細節。

mod %操作將始終執行完全除法,因此產生的余數小於除數。

x%y = x-(y *下限((x / y)))

帶有注釋的隨機范圍查找功能的示例:

uint32_t rand_range(uint32_t n, uint32_t m) {
    // size of range, inclusive
    const uint32_t length_of_range = m - n + 1;

    // add n so that we don't return a number below our range
    return (uint32_t)(rand() % length_of_range + n);
}

如上所述的另一個有趣的屬性:

如果x <y,則x%y = x

const uint32_t value = rand_range(1, RAND_MAX); // results in rand() % RAND_MAX + 1
// TRUE for all x = RAND_MAX, where x is the result of rand()
assert(value == RAND_MAX);
result of rand()
2 cents (ok 4 cents):

n = rand()
x = result
l = limit

n/RAND_MAX = x/l

Refactor:

(l/1)*(n/RAND_MAX) = (x/l)*(l/1)

Gives:

x = l*n/RAND_MAX

int randn(int limit)

{

    return limit*rand()/RAND_MAX;

}

int i;

for (i = 0; i < 100; i++) { 

    printf("%d ", randn(10)); 
    if (!(i % 16)) printf("\n"); 

}

> test
0
5 1 8 5 4 3 8 8 7 1 8 7 5 3 0 0
3 1 1 9 4 1 0 0 3 5 5 6 6 1 6 4
3 0 6 7 8 5 3 8 7 9 9 5 1 4 2 8
2 7 8 9 9 6 3 2 2 8 0 3 0 6 0 0
9 2 2 5 6 8 7 4 2 7 4 4 9 7 1 5
3 7 6 5 3 1 2 4 8 5 9 7 3 1 6 4
0 6 5

多次運行程序時,僅使用rand()將為您提供相同的隨機數。 即,當您第一次運行程序時,它將產生隨機數x,y和z。 如果再次運行該程序,那么它將產生與我觀察到的相同的x,y和z數。

我發現每次都保持唯一性的解決方案是使用srand()

這是附加代碼,

#include<stdlib.h>
#include<time.h>

time_t t;
srand((unsigned) time(&t));
int rand_number = rand() % (65 + 1 - 0) + 0 //i.e Random numbers in range 0-65.

要設置范圍,您可以使用公式:rand()%(max_number +1-minimum_number)+ minimum_number

希望能幫助到你!

如果您決定使用%方法 go,則需要重新滾動以獲得正確的分配。 但是,大多數時候您可以跳過重投,因為您只需要避免落在最后一個桶中的數字:

int rand_less_than(int max) {
    int last_bucket_min = RAND_MAX - RAND_MAX % max;
    int value;
    do {
        value = rand();
    } while (last_bucket_min <= value);

    return value % max;
}

請參閱@JarosrawPawlak的文章以獲取圖表說明: Random number generator using modulo

RAND_MAX < max的情況下,您需要擴展生成器:將隨機范圍從 1–5 擴展到 1–7

您可以通過在rand函數之前添加%來更改代碼

例如:

rand() % 50

會給您一個隨機數,范圍為50。對於您,將50替換為63或127

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM