2011-11-14 90 views
6

Tôi cần sự giúp đỡ của bạn và vui lòng cho tôi một số lời khuyên. Từ lập trình viên ngọc trai tôi biết rằng để tạo ra ngẫu nhiên số nguyên 30 bit chúng tôi nên viết nó như thế này:tạo ngẫu nhiên số nguyên 64 bit

RAND_MAX*rand()+rand() 

Nhưng những gì tôi có thể làm để tạo ra không 30, nhưng số nguyên 64 bit ngẫu nhiên để thay thế? Tôi nghĩ rằng đó là phương pháp rất kém hiệu quả nếu tôi nhân hai số nguyên 30 bit và sau đó nhân một lần nữa số nguyên 4 bit, vì vậy loại phương pháp tôi nên sử dụng? Tôi đang sử dụng popcount_1 phương pháp khác nhau cho 64 bit một và tôi muốn thử nghiệm nó trên số nguyên ngẫu nhiên (tôi cũng đo thời gian mà mỗi người cần để hoàn thành nhiệm vụ)

+0

bạn cũng có thể thay đổi và thêm chúng lên. – duedl0r

Trả lời

3

Đây có thể là một giải pháp, mà không cần nhân:

r30 = RAND_MAX*rand()+rand() 
s30 = RAND_MAX*rand()+rand() 
t4 = rand() & 0xf 

res = (r30 << 34) + (s30 << 4) + t4 
+1

Giả định rằng 'RAND_MAX' là 1 << 15. Nếu bạn _do_ giả định điều này, tại sao không: 'rand() + rand() << 15 + rand() << 30 + rand() << 45 + (rand() & 0xf) << 60'? Không có phép nhân nào cả. – MSalters

+1

Tại sao không chỉ làm một cái gì đó như 'return ((unsigned long long) rand() << 48) | ((unsigned long long) rand() << 32) | ((unsigned long long) rand() << 16) | ((unsigned long long) rand() & 0xffff); '? Ở đây bạn không có phép nhân, chỉ cần thay đổi. –

+0

Mặc dù, có, bạn có thể tạo 64 bit Có vẻ như với tôi độ phân giải của số ngẫu nhiên được tạo không thể lớn hơn số ngẫu nhiên. – Cris

2

Một 64 bit ngẫu nhiên int là bản chất 64 các bit ngẫu nhiên được hiểu là int.

Điền một mảng byte có độ dài 8 với byte ngẫu nhiên (see here for how) và diễn giải chúng dưới dạng int (see here for how).

+3

Tôi nghi ngờ rằng với hầu hết các lần triển khai 'rand() 'bạn * sẽ không * nhận được sự phân phối đặc biệt đồng đều bằng cách làm điều đó. – Flexo

3

Nếu boost là một tùy chọn, bạn có thể sử dụng boost random.

+0

bạn có chắc chắn rằng nó có thể tạo ra 64bit? Liên kết của bạn nói lên sự khác biệt: "mt19937 tạo ra các số nguyên trong phạm vi [0, 2^32-1]." – duedl0r

+0

Hãy xem các trình tạo khác nhau (http://www.boost.org/doc/libs/1_47_0/doc/html/boost_random/reference.html#boost_random.reference.generators), ví dụ tại 'ranlux64_3'. –

+1

@ duedl0r Nếu nó tạo ra một giá trị ngẫu nhiên tốt trong toàn bộ khoảng thời gian '[0, 2^32-1]', thì nó khá tầm thường để kết hợp hai cuộc gọi để tạo ra một giá trị ngẫu nhiên 64 bit tốt. (Đối với một định nghĩa hoàn toàn lỏng lẻo của "tốt", tất nhiên. Các máy phát điện cơ bản vẫn cần một khoảng thời gian 2^64 hoặc nhiều hơn, hoặc sẽ có rất nhiều giá trị mà không bao giờ có thể được tạo ra.) –

7

Đầu tiên, tôi đã nghi ngờ của tôi về các giải pháp bạn gửi cho 30 bit số nguyên. RAND_MAX chính nó có thể là một giá trị 31 bit, và RAND_MAX * rand() + rand() có khả năng tràn, tạo ra hành vi không xác định (và trong thực tế, giá trị âm).

Nếu bạn cần một giá trị lớn hơn mức tối thiểu đảm bảo của RAND_MAX, hoặc cho rằng vấn đề, bất cứ điều gì đó không phải là đáng kể nhỏ hơn RAND_MAX, giải pháp duy nhất sẽ được sử dụng cuộc gọi liên tiếp để rand(), và kết hợp nhưng bạn cần thực hiện điều này một cách cẩn thận và xác thực kết quả. (. Hầu hết các triển khai của rand() sử dụng tuyến tính máy phát điện đồng dư, mà còn thích hợp cho một số nhiệm vụ, không phải là đặc biệt tốt trong trường hợp này) Dù sao, cái gì đó như:

unsigned 
rand256() 
{ 
    static unsigned const limit = RAND_MAX - RAND_MAX % 256; 
    unsigned result = rand(); 
    while (result >= limit) { 
     result = rand(); 
    } 
    return result % 256; 
} 

unsigned long long 
rand64bits() 
{ 
    unsigned long long results = 0ULL; 
    for (int count = 8; count > 0; -- count) { 
     results = 256U * results + rand256(); 
    } 
    return results; 
} 

(Mã trong rand256 được thiết kế để loại bỏ các cách khác thiên vị không thể tránh khỏi bạn nhận được khi lập bản đồ RAND_MAX giá trị đến 256 giá trị)

+0

Làm cách nào để kiểm soát độ chính xác trong mã này. Giả sử tôi muốn tạo ra các số ngẫu nhiên 61 bit thay vì 64 bit. Tôi nghĩ nếu tôi bắt đầu đếm từ 7 thay vì 8, tôi sẽ nhận được một số ngẫu nhiên 56 bit. Tôi có đúng không? – arunmoezhi

+2

@arunmoezhi Nếu bạn có thể tạo 64 bit ngẫu nhiên, bạn có thể tạo ra 61 bằng cách tạo 64, và ném đi 3; ví dụ. bằng cách che giấu ba bit trên cùng. –

+0

có ý nghĩa. Cảm ơn. Giải pháp của bạn trông rất đẹp. Nhưng sẽ hữu ích hơn nếu bạn có thể thêm một số giải thích cho nó. Tôi mất một thời gian để hiểu bạn đang làm gì. – arunmoezhi

1

Một giải pháp chung:.

template <unsigned long long I> struct log2 { 
    static const int result = 1 + log2<I/2>::result; 
}; 
template <> struct log2<1> { 
    static const int result = 0; 
}; 

template <typename UINT> UINT genrand() { 
    UINT result = 0; 
    int bits = std::numeric_limits<UINT>::digits; 
    int rand_bits = log2<RAND_MAX>::result; 
    while (bits > 0) { 
    int r = rand(); 
    while (r >= (1<<rand_bits)) r = rand(); // Retry if too big. 
    result <<= rand_bits; 
    result += r; 
    bits -= rand_bits; 
    } 
    return result; 
} 

Sử dụng: unsigned long long R = genrand<unsigned long long>();.

Bộ đếm bits theo dõi số bit vẫn cần.

0

'Trả về giá trị tích phân giả ngẫu nhiên giữa 0 và RAND_MAX (bao gồm 0 và RAND_MAX)'. - http://en.cppreference.com/w/cpp/numeric/random/rand

Vì vậy, bạn nên sử dụng RAND_MAX + 1 (nó giống như tạo ra một chữ số bằng chữ số và sau đó chuyển đổi nó thành cơ số 10) thay vì RAND_MAX. Bằng cách này, bạn có thể tạo số bằng một, hai, ba chữ số vv trong cơ sở RAND_MAX + 1 (có thể với số 0 hàng đầu) và chuyển đổi thành số 10 và nhận số lượng lớn tùy ý.

Mọi thứ bạn có được lớn hơn MAX_VALUE mong muốn của mình có thể bị hủy và bạn vẫn nhận được xác suất 1/(MAX_VALUE + 1) để có được mỗi số. Lưu ý rằng phương pháp này có thể mất một lúc, đặc biệt nếu MAX_VALUE mong muốn của bạn nhỏ hơn rất nhiều so với giá trị tối đa có thể đạt được trước khi loại bỏ các số không mong muốn, như số bước mong đợi để có được ngẫu nhiên số trong [0, MAX_VALUE] với thuật toán này là: (MAX_OBTAINABLE_VALUE + 1)/(MAX_VALUE + 1)