2015-09-30 11 views
26

Theo kết quả sau, tạo số nguyên ngẫu nhiên đồng nhất giữa hai số sử dụng hoạt động % nhanh hơn gần 3 lần so với sử dụng std::uniform_int_distribution: Có lý do nào tốt để sử dụng std::uniform_int_distribution không?Lợi thế của việc sử dụng uniform_int_distribution so với hoạt động modulus là gì?

Code:

#include <iostream> 
#include <functional> 
#include <vector> 
#include <algorithm> 
#include <random> 

#include <cstdio> 
#include <cstdlib> 

using namespace std; 

#define N 100000000 

int main() 
{ 

clock_t tic,toc; 

for(int trials=0; trials<3; trials++) 
{ 
    cout<<"trial: "<<trials<<endl; 

    // uniform_int_distribution 
    { 
     int res = 0; 
     mt19937 gen(1); 
     uniform_int_distribution<int> dist(0,999); 

     tic = clock(); 
     for(int i=0; i<N; i++) 
     { 
      int r = dist(gen); 
      res += r; 
      res %= 1000; 
     } 
     toc = clock(); 
     cout << "uniform_int_distribution: "<<(float)(toc-tic)/CLOCKS_PER_SEC << endl; 
     cout<<res<<" "<<endl; 

    } 

    // simple modulus operation 
    { 
     int res = 0; 
     mt19937 gen(1); 

     tic = clock(); 
     for(int i=0; i<N; i++) 
     { 
      int r = gen()%1000; 
      res += r; 
      res %= 1000; 
     } 
     toc = clock(); 
     cout << "simple modulus operation: "<<(float)(toc-tic)/CLOCKS_PER_SEC << endl; 
     cout<<res<<" "<<endl; 

    } 

    cout<<endl; 
} 

} 

Output:

trial: 0 
uniform_int_distribution: 2.90289 
538 
simple modulus operation: 1.0232 
575 

trial: 1 
uniform_int_distribution: 2.86416 
538 
simple modulus operation: 1.01866 
575 

trial: 2 
uniform_int_distribution: 2.94309 
538 
simple modulus operation: 1.01809 
575 
+4

'std :: uniform_int_distribution' có thể tạo phân phối đồng đều giữa bất kỳ khoảng thời gian nguyên nào, trong khi'% 'không thể. – Lingxi

+19

Thật dễ dàng để viết mã nhanh nếu bạn không phải làm đúng. –

+6

https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful –

Trả lời

39

Bạn sẽ nhận được thiên vị thống kê khi bạn sử dụng modulo (%) để lập bản đồ loạt các ví dụ rand() đến một khoảng thời gian khác.

Ví dụ: giả sử rand() bản đồ thống nhất (không thiên vị) đến [0, 32767] và bạn muốn ánh xạ tới [0,4] làm rand() % 5. Sau đó, các giá trị 0, 1 và 2 trung bình sẽ được tạo ra 6554 trong số 32768 lần, nhưng giá trị 3 và 4 chỉ 6553 lần (sao cho 3 * 6554 + 2 * 6553 = 32768).

Độ lệch nhỏ (0,01%) nhưng tùy thuộc vào ứng dụng của bạn có thể gây tử vong. Xem bài nói chuyện của Stephan T. Lavavej "rand() considered harmful" để biết thêm chi tiết.

+1

Để công bằng, một hệ quả là nếu mô đun là một công suất không đổi của hai, thì '%' rsp. '&' có thể nhanh hơn 'uniform_int_distribution', và không có sự sai lệch nào được đưa vào các triển khai thông thường. –

+0

@ArneVogel đúng, nhưng chỉ khi RAND_MAX cũng là một sức mạnh của 2. Giá trị này phụ thuộc vào việc triển khai thực hiện. Nó được đảm bảo rằng giá trị này là ít nhất 32767. Đối với mã di động và các giao diện chung, chỉ cần sử dụng 'uniform_int_distribution'. – TemplateRex

+0

@ArneVogel Trông giống như vấn đề QOI, phải không? Nhưng, nếu bạn có một số ngẫu nhiên với các bit X của entropy đó là Y bit rộng với entropy lây lan thống nhất, nếu bạn trích xuất các bit Z thấp hơn, bạn kết thúc với các bit X * Z/Y của entropy. Thay vào đó, nếu bạn thay đổi tất cả các bit Y thành kết quả của bạn (một hệ thống thay đổi-xor đơn giản), đầu ra của bạn vẫn có thể có tới các bit x của entropy (giả sử X <= Z). – Yakk

Các vấn đề liên quan