Tạo số nguyên ngẫu nhiên từ một phạm vi


157

Tôi cần một hàm sẽ tạo một số nguyên ngẫu nhiên trong phạm vi nhất định (bao gồm các giá trị viền). Tôi không yêu cầu chất lượng / ngẫu nhiên không hợp lý, tôi có bốn yêu cầu:

  • Tôi cần nó để được nhanh chóng. Dự án của tôi cần tạo ra hàng triệu (hoặc đôi khi thậm chí hàng chục triệu) số ngẫu nhiên và chức năng tạo hiện tại của tôi đã được chứng minh là một nút cổ chai.
  • Tôi cần nó để được thống nhất hợp lý (sử dụng rand () là hoàn toàn tốt).
  • phạm vi tối thiểu có thể là bất cứ thứ gì từ <0, 1> đến <-32727, 32727>.
  • nó phải được gieo hạt

Tôi hiện đang có mã C ++ sau đây:

output = min + (rand() * (int)(max - min) / RAND_MAX)

Vấn đề là, nó không thực sự đồng nhất - max chỉ được trả về khi rand () = RAND_MAX (đối với Visual C ++ là 1/32727). Đây là vấn đề chính đối với các phạm vi nhỏ như <-1, 1>, trong đó giá trị cuối cùng gần như không bao giờ được trả về.

Vì vậy, tôi lấy bút và giấy và đưa ra công thức sau (được xây dựng trên thủ thuật làm tròn số nguyên (int) (n + 0,5)):

nhập mô tả hình ảnh ở đây

Nhưng nó vẫn không cho tôi phân phối thống nhất. Các lần chạy lặp lại với 10000 mẫu cho tôi tỷ lệ 37:50:13 cho các giá trị giá trị -1, 0. 1.

Bạn có thể vui lòng đề nghị công thức tốt hơn? (hoặc thậm chí toàn bộ hàm tạo số giả ngẫu nhiên)



3
@Bill MaGriff: có. Nó có cùng một vấn đề. Một phiên bản đơn giản là: làm thế nào bạn có thể chia 10 miếng kẹo cho 3 đứa trẻ một cách đồng đều (mà không làm vỡ bất kỳ viên kẹo nào)? Câu trả lời là, bạn không thể - bạn phải đưa ba cho mỗi đứa trẻ, và chỉ không đưa đứa thứ mười cho bất kỳ ai.
Jerry Coffin

5
Bạn đã xem Boost.Random chưa?
Fred Nurk

3
Kiểm tra bài viết của Andrew Koenig "Một vấn đề đơn giản gần như không bao giờ được giải quyết chính xác": drdobbs.com/blog/archives/2010/11/a_simple_proble.html
Gene Bushuyev

1
@Gene Bushuyev: Cả Andrew và tôi đã làm quen với chủ đề này khá lâu rồi. Xem: Groups.google.com/group/comp.lang.c++/browse_frm/thread/ , và: Groups.google.com.vn/group/comp.os.ms-windows.programmer.tools.mfc/ trộm
Jerry Coffin

Câu trả lời:


105

Một giải pháp nhanh, có phần tốt hơn của bạn, nhưng vẫn chưa được phân phối thống nhất

output = min + (rand() % static_cast<int>(max - min + 1))

Ngoại trừ khi kích thước của phạm vi là lũy thừa bằng 2, phương pháp này tạo ra các số phân phối không đồng nhất sai lệch bất kể chất lượng của rand(). Để kiểm tra toàn diện về chất lượng của phương pháp này, xin vui lòng đọc này .


2
Cảm ơn, điều này dường như đủ tốt cho tôi từ các bài kiểm tra nhanh - phân phối của nó cho -1, 0, 1 là gần 33:33:33.
Matěj Zábský

3
Nó trả về giá trị tối đa luôn. Tôi có thiếu gì ở đây không? : |
rohan-patel

15
rand()nên được coi là có hại trong C ++ có nhiều cách tốt hơn để có được thứ gì đó được phân phối đồng đều và thực sự ngẫu nhiên.
Mgetz

1
Nó thực sự trả về một số chính xác trong phạm vi 100% thời gian? Tôi đã tìm thấy một số câu trả lời stackoverflow khác ở đây đang sử dụng đệ quy để thực hiện "đúng cách": stackoverflow.com/a/6852394/623622
Czarek Tomczak

2
Vì đây là một câu trả lời được đánh giá cao (hơn mong muốn), có vẻ là nguồn thông tin đáng tin cậy cho nhiều độc giả mới, tôi nghĩ rằng việc đề cập đến chất lượng và các mối nguy hiểm tiềm tàng của giải pháp này là rất quan trọng, vì vậy tôi đã chỉnh sửa.
plasmacel

296

Câu trả lời đơn giản nhất (và do đó tốt nhất) C ++ (sử dụng tiêu chuẩn 2011) là

#include <random>

std::random_device rd;     // only used once to initialise (seed) engine
std::mt19937 rng(rd());    // random-number engine used (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased

auto random_integer = uni(rng);

Không cần phải sáng chế lại bánh xe. Không cần phải lo lắng về sự thiên vị. Không cần phải lo lắng về việc sử dụng thời gian như hạt giống ngẫu nhiên.


1
Ngày nay điều này nên là câu trả lời . Tham chiếu tạo số giả ngẫu nhiên cho nhiều tính năng hơn.
alextoind

8
Tôi đồng ý về "đơn giản nhất" (và thành ngữ nhất), không phải là "tốt nhất". Thật không may, Tiêu chuẩn không đảm bảo random_device, có thể bị phá vỡ hoàn toàn trong một số trường hợp . Hơn nữa, mt19937trong khi lựa chọn mục đích chung rất tốt, không phải là máy phát điện chất lượng tốt nhất (xem so sánh này ) và do đó có thể không phải là ứng cử viên lý tưởng cho OP.
Alberto M

1
@AlbertoM Thật không may, so sánh mà bạn đề cập đến không cung cấp đủ chi tiết và không thể lặp lại, điều này làm cho nó trở nên đáng ngờ (hơn nữa, đó là từ năm 2015, trong khi câu trả lời của tôi có từ năm 2013). Có thể đúng là có những phương pháp tốt hơn xung quanh (và hy vọng trong tương lai, minstdsẽ là một phương pháp như vậy), nhưng đó là sự tiến bộ. Đối với việc triển khai kém random_device- điều đó thật kinh khủng và nên được coi là một lỗi (cũng có thể là của tiêu chuẩn C ++, nếu nó cho phép).
Walter

1
Tôi hoàn toàn đồng ý với bạn; Tôi không thực sự muốn chỉ trích giải pháp của bạn cho mỗi gia nhập , chỉ muốn cảnh báo người đọc ngẫu nhiên mà câu trả lời dứt khoát về vấn đề này, bất chấp những lời hứa của C ++ 11, vẫn chưa được viết ra. Tôi sẽ đăng một cái nhìn tổng quan về chủ đề này vào năm 2015 như là câu trả lời cho một câu hỏi liên quan .
Alberto M

1
Đó là "đơn giản nhất"? Bạn có thể giải thích tại sao rõ ràng đơn giản hơn nhiều rand()không phải là một tùy chọn và nó có quan trọng đối với việc sử dụng không quan trọng, như tạo ra một chỉ số trục ngẫu nhiên không? Ngoài ra, tôi có phải lo lắng về việc xây dựng random_device/ mt19937/ uniform_int_distributiontrong một vòng lặp chặt chẽ / chức năng nội tuyến không? Tôi có nên vượt qua chúng?
bluenote10

60

Nếu trình biên dịch của bạn hỗ trợ C ++ 0x và sử dụng nó là một tùy chọn cho bạn, thì tiêu <random>đề tiêu chuẩn mới có khả năng đáp ứng nhu cầu của bạn. Nó có chất lượng cao uniform_int_distributionsẽ chấp nhận giới hạn tối thiểu và tối đa (bao gồm khi bạn cần) và bạn có thể chọn trong số các trình tạo số ngẫu nhiên khác nhau để cắm vào phân phối đó.

Đây là mã tạo ra một triệu ints ngẫu nhiên được phân phối đồng đều trong [-57, 365]. Tôi đã sử dụng các <chrono>thiết bị tiêu chuẩn mới để tính thời gian khi bạn đề cập đến hiệu suất là mối quan tâm chính đối với bạn.

#include <iostream>
#include <random>
#include <chrono>

int main()
{
    typedef std::chrono::high_resolution_clock Clock;
    typedef std::chrono::duration<double> sec;
    Clock::time_point t0 = Clock::now();
    const int N = 10000000;
    typedef std::minstd_rand G;
    G g;
    typedef std::uniform_int_distribution<> D;
    D d(-57, 365);
    int c = 0;
    for (int i = 0; i < N; ++i) 
        c += d(g);
    Clock::time_point t1 = Clock::now();
    std::cout << N/sec(t1-t0).count() << " random numbers per second.\n";
    return c;
}

Đối với tôi (2,8 GHz Intel Core i5), bản in này:

2.10268e + 07 số ngẫu nhiên mỗi giây.

Bạn có thể khởi tạo trình tạo bằng cách chuyển một int đến hàm tạo của nó:

    G g(seed);

Nếu sau này bạn thấy rằng intkhông bao gồm phạm vi bạn cần cho phân phối của mình, điều này có thể được khắc phục bằng cách thay đổi uniform_int_distributiontương tự (ví dụ như long long):

    typedef std::uniform_int_distribution<long long> D;

Nếu sau này bạn thấy rằng đó minstd_randkhông phải là một trình tạo chất lượng đủ cao, thì nó cũng có thể dễ dàng bị tráo đổi. Ví dụ:

    typedef std::mt19937 G;  // Now using mersenne_twister_engine

Có quyền kiểm soát riêng đối với trình tạo số ngẫu nhiên và phân phối ngẫu nhiên có thể khá tự do.

Tôi cũng đã tính toán (không hiển thị) 4 "khoảnh khắc" đầu tiên của phân phối này (sử dụng minstd_rand) và so sánh chúng với các giá trị lý thuyết trong nỗ lực định lượng chất lượng của phân phối:

min = -57
max = 365
mean = 154.131
x_mean = 154
var = 14931.9
x_var = 14910.7
skew = -0.00197375
x_skew = 0
kurtosis = -1.20129
x_kurtosis = -1.20001

( x_Tiền tố đề cập đến "dự kiến")


3
Câu trả lời này có thể sử dụng một đoạn mã tóm tắt ngắn chỉ hiển thị mã thực sự cần thiết để tạo một số nguyên ngẫu nhiên từ một phạm vi.
arekolek

Vấn đề được thực hiện dễ dàng hơn bởi thực tế là tối thiểu và tối đa của phân phối không bao giờ thay đổi. Điều gì nếu bạn phải tạo ra dở mỗi lần lặp với các giới hạn khác nhau? Bao nhiêu nó sẽ làm chậm vòng lặp?
quant_dev

15

Hãy chia vấn đề thành hai phần:

  • Tạo một số ngẫu nhiên ntrong phạm vi từ 0 đến (tối đa).
  • Thêm min vào số đó

Phần đầu tiên rõ ràng là khó nhất. Giả sử giá trị trả về của rand () là hoàn toàn đồng nhất. Sử dụng modulo sẽ thêm độ lệch cho các (RAND_MAX + 1) % (max-min+1)số đầu tiên . Vì vậy, nếu chúng ta có thể thay đổi một cách kỳ diệu RAND_MAXthành RAND_MAX - (RAND_MAX + 1) % (max-min+1), sẽ không còn bất kỳ sự thiên vị nào nữa.

Nó chỉ ra rằng chúng ta có thể sử dụng trực giác này nếu chúng ta sẵn sàng cho phép giả thuyết không giả định vào thời gian chạy thuật toán của chúng ta. Bất cứ khi nào rand () trả về một số quá lớn, chúng ta chỉ cần yêu cầu một số ngẫu nhiên khác cho đến khi chúng ta có được một số đủ nhỏ.

Thời gian chạy hiện được phân phối hình học , với giá trị dự kiến 1/ptrong đó pxác suất nhận được một số đủ nhỏ trong lần thử đầu tiên. Vì RAND_MAX - (RAND_MAX + 1) % (max-min+1)luôn luôn nhỏ hơn (RAND_MAX + 1) / 2, chúng tôi biết rằng p > 1/2, vì vậy số lần lặp dự kiến ​​sẽ luôn ít hơn hai cho bất kỳ phạm vi nào. Có thể tạo ra hàng chục triệu số ngẫu nhiên trong chưa đầy một giây trên CPU tiêu chuẩn với kỹ thuật này.

BIÊN TẬP:

Mặc dù những điều trên là đúng về mặt kỹ thuật, câu trả lời của DSimon có lẽ hữu ích hơn trong thực tế. Bạn không nên tự thực hiện những thứ này. Tôi đã thấy rất nhiều triển khai lấy mẫu từ chối và thường rất khó để xem liệu nó có đúng hay không.


Để hoàn thiện: Đây là Lấy mẫu từ chối .
etarion

3
Sự thật thú vị: Joel Spolsky đã từng đề cập đến một phiên bản của câu hỏi này như một ví dụ về những gì StackOverflow trả lời tốt. Tôi nhìn qua các câu trả lời trên trang web liên quan đến lấy mẫu từ chối lúc bấy giờ và mỗi đơn một là không chính xác.
Jørgen Fogh

13

Làm thế nào về Mersenne Twister ? Việc thực hiện boost khá dễ sử dụng và được thử nghiệm tốt trong nhiều ứng dụng trong thế giới thực. Tôi đã sử dụng nó trong một số dự án học thuật như trí tuệ nhân tạo và thuật toán tiến hóa.

Đây là ví dụ của họ, nơi họ tạo ra một chức năng đơn giản để lăn một cái chết sáu mặt:

#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>

boost::mt19937 gen;

int roll_die() {
    boost::uniform_int<> dist(1, 6);
    boost::variate_generator<boost::mt19937&, boost::uniform_int<> > die(gen, dist);
    return die();
}

Ồ, và đây là một số chi tiết khác của máy phát điện này trong trường hợp bạn không tin rằng bạn nên sử dụng nó trên mức độ thấp hơn nhiều rand():

Mersenne Twister là một máy phát "số ngẫu nhiên" được phát minh bởi Makoto Matsumoto và Takuji Nishimura; trang web của họ bao gồm nhiều triển khai thuật toán.

Về cơ bản, Mersenne Twister là một thanh ghi dịch chuyển phản hồi tuyến tính rất lớn. Thuật toán hoạt động trên hạt giống 19.937 bit, được lưu trữ trong một mảng 624 phần tử gồm các số nguyên không dấu 32 bit. Giá trị 2 ^ 19937-1 là số nguyên tố Mersenne; kỹ thuật điều khiển hạt giống dựa trên thuật toán "xoắn" cũ hơn - do đó có tên là "Mersenne Twister".

Một khía cạnh hấp dẫn của Mersenne Twister là việc sử dụng các hoạt động nhị phân - trái ngược với phép nhân tốn thời gian - để tạo số. Thuật toán cũng có một khoảng thời gian rất dài và độ chi tiết tốt. Nó vừa nhanh và hiệu quả cho các ứng dụng phi mật mã.


1
Twister Mersenne là một máy phát tốt, nhưng vấn đề anh ta xử lý vẫn còn, bất kể chính máy phát điện bên dưới.
Jerry Coffin

Tôi không muốn sử dụng Boost chỉ cho trình tạo ngẫu nhiên, bởi vì (vì dự án của tôi là thư viện) nên nó có nghĩa là giới thiệu một phụ thuộc khác cho dự án. Tôi có thể sẽ bị buộc phải sử dụng nó dù sao trong tương lai, vì vậy sau đó tôi có thể chuyển sang máy phát điện này.
Matěj Zábský

1
@Jerry Coffin Vấn đề gì? Tôi đã cung cấp nó bởi vì nó đáp ứng tất cả các yêu cầu của anh ấy: nó nhanh, đồng nhất (sử dụng boost::uniform_intphân phối), bạn có thể chuyển đổi phạm vi tối đa tối thiểu thành bất cứ điều gì bạn thích và có thể gieo hạt.
Aphex

@mzabsky Có lẽ tôi sẽ không để điều đó ngăn cản tôi, khi tôi phải gửi các dự án của mình cho các giáo sư của mình để nộp, tôi chỉ bao gồm các tệp tiêu đề tăng cường có liên quan mà tôi đang sử dụng; bạn không cần phải gói toàn bộ thư viện boost 40mb bằng mã của mình. Tất nhiên trong trường hợp của bạn, điều này có thể không khả thi vì các lý do khác như bản quyền ...
Aphex

@Aphex Dự án của tôi không thực sự là một trình giả lập khoa học hoặc một cái gì đó cần phân phối thực sự thống nhất. Tôi đã sử dụng trình tạo cũ trong 1,5 năm mà không gặp vấn đề gì, tôi chỉ nhận thấy phân phối sai lệch khi lần đầu tiên tôi cần nó để tạo số từ phạm vi rất nhỏ (3 trong trường hợp này). Tốc độ vẫn là đối số để xem xét các giải pháp tăng mặc dù. Tôi sẽ xem xét giấy phép của nó để xem liệu tôi có thể chỉ cần thêm một vài tệp cần thiết vào dự án của mình không - tôi thích "Thanh toán -> F5 -> sẵn sàng để sử dụng" như hiện tại.
Matěj Zábský

11
int RandU(int nMin, int nMax)
{
    return nMin + (int)((double)rand() / (RAND_MAX+1) * (nMax-nMin+1));
}

Đây là ánh xạ của 32768 số nguyên đến (nMax-nMin + 1) số nguyên. Ánh xạ sẽ khá tốt nếu (nMax-nMin + 1) nhỏ (như trong yêu cầu của bạn). Tuy nhiên, xin lưu ý rằng nếu (nMax-nMin + 1) lớn, ánh xạ sẽ không hoạt động (Ví dụ: bạn không thể ánh xạ 32768 giá trị thành 30000 giá trị với xác suất bằng nhau). Nếu các phạm vi như vậy là cần thiết - bạn nên sử dụng nguồn ngẫu nhiên 32 bit hoặc 64 bit, thay vì rand 15 bit () hoặc bỏ qua các kết quả rand () nằm ngoài phạm vi.


Mặc dù không phổ biến, đây cũng là những gì tôi sử dụng cho các dự án phi khoa học của mình. Dễ hiểu (bạn không cần bằng cấp toán học) và thực hiện đầy đủ (không bao giờ phải lập hồ sơ bất kỳ mã nào sử dụng nó). :) Trong trường hợp phạm vi lớn, tôi đoán chúng ta có thể kết hợp hai giá trị rand () với nhau và nhận giá trị 30 bit để làm việc với (giả sử RAND_MAX = 0x7fff, tức là 15 bit ngẫu nhiên)
efotinis

thay đổi RAND_MAXđể (double) RAND_MAXtránh cảnh báo tràn số nguyên.
alex

4

Đây là một phiên bản không thiên vị tạo ra các số trong [low, high]:

int r;
do {
  r = rand();
} while (r < ((unsigned int)(RAND_MAX) + 1) % (high + 1 - low));
return r % (high + 1 - low) + low;

Nếu phạm vi của bạn nhỏ một cách hợp lý, không có lý do gì để lưu trữ phía bên phải của so sánh trong dovòng lặp.


IMO, không có giải pháp nào được trình bày ở đó thực sự có nhiều cải tiến. Giải pháp dựa trên vòng lặp của ông hoạt động, nhưng có thể khá kém hiệu quả, đặc biệt là đối với một phạm vi nhỏ như OP thảo luận. Giải pháp lệch đồng phục của anh ấy thực sự không tạo ra sự sai lệch đồng phục nào cả. Nhiều nhất là loại ngụy trang thiếu đồng bộ.
Jerry Coffin

@Jerry: Vui lòng kiểm tra phiên bản mới.
Jeremiah Willcock

Tôi có một chút không chắc chắn về việc làm việc chính xác. Nó có thể, nhưng sự đúng đắn dường như không rõ ràng, ít nhất là với tôi.
Jerry Coffin

@Jerry: Đây là lý do của tôi: Giả sử phạm vi là [0, h)đơn giản. Gọi rand()RAND_MAX + 1giá trị trả về có thể; lấy rand() % hsự sụp đổ (RAND_MAX + 1) / hcủa chúng cho từng hgiá trị đầu ra, ngoại trừ (RAND_MAX + 1) / h + 1chúng được ánh xạ tới các giá trị nhỏ hơn (RAND_MAX + 1) % h(vì chu kỳ một phần cuối cùng thông qua các hđầu ra). Do đó, chúng tôi loại bỏ (RAND_MAX + 1) % hcác đầu ra có thể để có được một phân phối không thiên vị.
Jeremiah Willcock

3

Tôi khuyên dùng thư viện Boost.Random , nó siêu chi tiết và được ghi chép đầy đủ, cho phép bạn chỉ định rõ ràng phân phối nào bạn muốn và trong các tình huống phi mã hóa thực sự có thể vượt trội hơn so với triển khai rand thư viện C điển hình.


1

giả sử min và max là các giá trị int, [và] có nghĩa là bao gồm giá trị này, (và) có nghĩa là không bao gồm giá trị này, sử dụng ở trên để lấy giá trị đúng bằng c ++ rand ()

tham khảo: for () [] xác định, truy cập:

https://en.wikipedia.org/wiki/Interval_(mathatures)

để biết hàm rand và srand hoặc RAND_MAX xác định, hãy truy cập:

http://en.cppreference.com/w/cpp/numeric/random/rand

[nhỏ nhất lớn nhất]

int randNum = rand() % (max - min + 1) + min

(nhỏ nhất lớn nhất]

int randNum = rand() % (max - min) + min + 1

[nhỏ nhất lớn nhất)

int randNum = rand() % (max - min) + min

(nhỏ nhất lớn nhất)

int randNum = rand() % (max - min - 1) + min + 1

0

Trong chủ đề từ chối lấy mẫu này đã được thảo luận, nhưng tôi muốn đề xuất một tối ưu hóa dựa trên thực tế rand() % 2^somethingkhông đưa ra bất kỳ sự thiên vị nào như đã đề cập ở trên.

Thuật toán thực sự đơn giản:

  • tính công suất nhỏ nhất bằng 2 lớn hơn chiều dài khoảng
  • chọn ngẫu nhiên một số trong khoảng "mới" đó
  • trả về số đó nếu nó nhỏ hơn độ dài của khoảng thời gian ban đầu
    • từ chối khác

Đây là mã mẫu của tôi:

int randInInterval(int min, int max) {
    int intervalLen = max - min + 1;
    //now calculate the smallest power of 2 that is >= than `intervalLen`
    int ceilingPowerOf2 = pow(2, ceil(log2(intervalLen)));

    int randomNumber = rand() % ceilingPowerOf2; //this is "as uniform as rand()"

    if (randomNumber < intervalLen)
        return min + randomNumber;      //ok!
    return randInInterval(min, max);    //reject sample and try again
} 

Điều này hoạt động tốt đặc biệt là trong các khoảng nhỏ, vì sức mạnh của 2 sẽ "gần" hơn với độ dài khoảng thời gian thực, và do đó số lần bỏ lỡ sẽ nhỏ hơn.

PS
Rõ ràng tránh việc đệ quy sẽ hiệu quả hơn (không cần tính toán nhiều lần trên trần log ..) nhưng tôi nghĩ rằng nó dễ đọc hơn cho ví dụ này.


0

Lưu ý rằng trong hầu hết các đề xuất, giá trị ngẫu nhiên ban đầu mà bạn có được từ hàm rand (), thường là từ 0 đến RAND_MAX, đơn giản là bị lãng phí. Bạn chỉ tạo một số ngẫu nhiên trong số đó, trong khi có một quy trình âm thanh có thể cung cấp cho bạn nhiều hơn.

Giả sử rằng bạn muốn [min, max] vùng số ngẫu nhiên nguyên. Chúng tôi bắt đầu từ [0, tối đa]

Lấy cơ sở b = max-min + 1

Bắt đầu từ việc đại diện cho một số bạn nhận được từ rand () trong cơ sở b.

Bằng cách đó, bạn đã có sàn (log (b, RAND_MAX)) vì mỗi chữ số trong cơ sở b, ngoại trừ có thể là chữ số cuối cùng, biểu thị một số ngẫu nhiên trong phạm vi [0, tối đa].

Tất nhiên, sự thay đổi cuối cùng thành [min, max] là đơn giản cho mỗi số ngẫu nhiên r + min.

int n = NUM_DIGIT-1;
while(n >= 0)
{
    r[n] = res % b;
    res -= r[n];
    res /= b;
    n--;
}

Nếu NUM_DIGIT là số chữ số trong cơ sở b mà bạn có thể trích xuất và đó là

NUM_DIGIT = floor(log(b,RAND_MAX))

sau đó, đây là một cách đơn giản để trích xuất các số ngẫu nhiên NUM_DIGIT từ 0 đến b-1 trong số một số ngẫu nhiên RAND_MAX cung cấp b <RAND_MAX.


-1

Công thức cho việc này rất đơn giản, vì vậy hãy thử biểu thức này,

 int num = (int) rand() % (max - min) + min;  
 //Where rand() returns a random number between 0.0 and 1.0

2
Toàn bộ vấn đề đã sử dụng rand của C / C ++, trả về số nguyên trong một phạm vi được chỉ định bởi thời gian chạy. Như đã trình bày trong luồng này, ánh xạ các số nguyên ngẫu nhiên từ [0, RAND_MAX] sang [MIN, MAX] không hoàn toàn đơn giản, nếu bạn muốn tránh phá hủy các thuộc tính hoặc hiệu suất thống kê của chúng. Nếu bạn có gấp đôi trong phạm vi [0, 1], việc ánh xạ rất dễ dàng.
Matěj Zábský

2
Câu trả lời của bạn là sai, bạn nên sử dụng mô-đun thay thế:int num = (int) rand() % (max - min) + min;
Jaime Ivan Cervantes

-2

Biểu thức sau đây không được thiên vị nếu tôi không nhầm:

std::floor( ( max - min + 1.0 ) * rand() ) + min;

Tôi giả sử ở đây rằng rand () cung cấp cho bạn một giá trị ngẫu nhiên trong phạm vi từ 0,0 đến 1,0 KHÔNG bao gồm 1,0 và tối đa và tối thiểu là các số nguyên với điều kiện tối thiểu <max.


std::floortrả về double, và chúng ta cần một giá trị nguyên ở đây. Tôi sẽ chỉ intsử dụng thay vì sử dụng std::floor.
musiphil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.