2010-06-08 57 views
13

thể trùng lặp:
Generating Random Numbers in Objective-CTạo một số ngẫu nhiên trong phạm vi?

Làm thế nào để tạo ra một số ngẫu nhiên đó là trong một phạm vi?

+4

Trùng lặp - f.e. http://stackoverflow.com/questions/160890/generating-random-numbers-in-objective-c – schnaader

+0

Bạn đã thử tìm kiếm chưa? Điều này đã được yêu cầu một nửa tá tốt trước đây. Ngoài ra, tất cả các câu trả lời dưới đây là sai theo nghĩa là 'rand' không phải là một RNG tốt và yêu cầu gieo hạt. Thay vào đó, bạn nên sử dụng 'arc4random'. –

+0

@Dave: không đảm bảo rằng 'rand()' nhất thiết là xấu, chỉ không đảm bảo rằng nó tốt. Đề xuất arc4random mà không biết mục đích dự định làm cho ít (nếu có) ý nghĩa. Hầu hết người mới bắt đầu không làm bất cứ điều gì mà chất lượng của máy phát điện thực sự quan trọng anyway. –

Trả lời

52

Đây thực sự là một chút khó khăn hơn để có được sự chính xác hơn so với hầu hết mọi người nhận ra:

int rand_lim(int limit) { 
/* return a random number between 0 and limit inclusive. 
*/ 

    int divisor = RAND_MAX/(limit+1); 
    int retval; 

    do { 
     retval = rand()/divisor; 
    } while (retval > limit); 

    return retval; 
} 

Nỗ lực chỉ sử dụng % (hoặc tương đương, /) để có được các con số trong phạm vi gần như chắc chắn giới thiệu skew (tức là, một số con số sẽ được tạo thường xuyên hơn những người khác).

Vì sao phải sử dụng % tạo ra kết quả sai lệch: trừ khi phạm vi bạn muốn là ước số của RAND_MAX, sai lệch là không thể tránh khỏi. Nếu bạn bắt đầu với số lượng nhỏ, nó khá dễ dàng để xem lý do tại sao. Cân nhắc lấy 10 miếng kẹo và cố gắng phân chia đều giữa ba đứa trẻ. Rõ ràng nó không thể được thực hiện - nếu bạn đưa ra tất cả các kẹo, gần nhất bạn có thể nhận được là cho hai đứa trẻ để có được ba miếng kẹo, và một trong số họ nhận được bốn.

Chỉ có một cách để tất cả trẻ em có cùng số lượng kẹo: đảm bảo bạn không đưa ra miếng kẹo cuối cùng.

Để liên kết điều này với mã ở trên, hãy bắt đầu bằng cách đánh số kẹo từ 1 đến 10 và trẻ em từ 1 đến 3. Bộ phận ban đầu cho biết vì có ba trẻ em, số chia của chúng tôi là ba. Sau đó, chúng tôi lấy kẹo ngẫu nhiên từ thùng, nhìn vào số của nó và chia cho ba và đưa nó cho đứa trẻ đó - nhưng nếu kết quả lớn hơn 3 (nghĩa là chúng tôi đã chọn kẹo số 10), chúng tôi không đưa nó ra - chúng tôi loại bỏ nó và chọn một kẹo khác.

Tất nhiên, nếu bạn đang sử dụng triển khai C++ hiện đại (ví dụ: hỗ trợ C++ 11 hoặc mới hơn), bạn thường nên sử dụng một lớp học distribution từ thư viện chuẩn. Mã trên tương ứng chặt chẽ nhất với std::uniform_int_distribution, nhưng thư viện chuẩn cũng bao gồm uniform_real_distribution cũng như các lớp cho một số bản phân phối không đồng đều (Bernoulli, Poisson, bình thường, có thể là một vài người khác mà tôi không nhớ tại thời điểm này).

+5

Tôi xin lỗi, nhưng ewww! Điều cuối cùng tôi muốn làm là lặp lại một phân chia một số không xác định (ai biết, có lẽ mãi mãi) của thời gian khi cố gắng để có được một số ngẫu nhiên. Skew hay không, tôi sẽ đơn giản hơn hoặc có lẽ là một giải pháp điều khiển bảng. –

+3

@Michael: thử nó trước khi yo nhảy tới bất kỳ kết luận nào. Trong thực tế, "số không xác định" là * thường * 1. Trừ khi bạn làm điều này trong một vòng lặp * thực sự * chặt chẽ (ví dụ, điền một vectơ với các số ngẫu nhiên) thì hầu như không thể đo được điều này chậm hơn các phiên bản rõ ràng sai rồi. –

+4

Đây là kỹ thuật chính xác nhưng bạn có một vấn đề GIGO bắt đầu với rand(). Có vẻ như bạn đang cố sửa sai lệch khi giới hạn không phải là yếu tố của RAND_MAX, bằng cách sử dụng phương pháp phân chia mô-đun lỗi của bạn là thứ tự 'giới hạn/RAND_MAX' cho đến khi' giới hạn' tiếp cận 'RAND_MAX'. Các vấn đề bắt đầu với một PRNG như Rand() lùn hiệu ứng như thế. Giá bạn trả là giới thiệu một vòng lặp phi derterministic với thời gian chạy không bị ràng buộc [IRL nó chạy một lần nhưng chúng tôi đang tách lông ở đây ;-)] và bạn không đạt được gì vì Rand là crap để bắt đầu với. – Ukko

7
int rand_range(int min_n, int max_n) 
{ 
    return rand() % (max_n - min_n + 1) + min_n; 
} 

Đối với phân số:

double rand_range(double min_n, double max_n) 
{ 
    return (double)rand()/RAND_MAX * (max_n - min_n) + min_n; 
} 
+4

Điều này sẽ không cung cấp cho một phân phối thống nhất (trừ quyền hạn của hai). –

+2

Tôi biết, nhưng nó hoạt động nhanh, và phân phối là ok cho các phạm vi nhỏ. Nó là tốt cho gamecoding. Dù sao, tôi nên viết điều này ở đâu đó trong câu trả lời. –

+1

@Oli, ai quan tâm? Xem bình luận của Ukko trong câu trả lời ở trên. Nếu bạn đang sử dụng rand() để bắt đầu với, số lượng teeny của skew (cho max_n-min_n tương đối nhỏ) là ít nhất của bạn lo lắng. – user168715

-1

tôi đã viết này đặc trưng trong obj-C cho một dự án iPhone:

- (int) intInRangeMinimum:(int)min andMaximum:(int)max { 
    if (min > max) { return -1; } 
    int adjustedMax = (max + 1) - min; // arc4random returns within the set {min, (max - 1)} 
    int random = arc4random() % adjustedMax; 
    int result = random + min; 
    return result; 
} 

Cách sử dụng:

int newNumber = [aClass intInRangeMinimum:1 andMaximum:100]; 

Thêm muối nếm

+0

Giải pháp đó vẫn có độ lệch được giới thiệu bởi số học mô-đun. Vì bạn đang sử dụng thư viện arc4, nó cung cấp cho bạn chính xác các thói quen mà bạn muốn gọi là 'arc4random_uniform' cho kết quả thống nhất. chỉ cần thay đổi một dòng thành int random = arc4random_uniform (adjustmentMax); –

2

Đối với một giá trị số nguyên trong khoảng [ tối thiểu, tối đa):

double scale = (double) (max - min)/RAND_MAX; 
int val = min + floor(rand() * scale) 
+2

cho các newbs, bạn sẽ phải bao gồm '#include ' –

-2
+(NSInteger)randomNumberWithMin:(NSInteger)min WithMax:(NSInteger)max { 
    if (min>max) { 
     int tempMax=max; 
     max=min; 
     min=tempMax; 
    } 
    int randomy=arc4random() % (max-min+1); 
    randomy=randomy+min; 
    return randomy; 
} 

Tôi sử dụng phương pháp này trong một lớp liên quan đến số ngẫu nhiên mà tôi đã tạo. Hoạt động tốt cho các nhu cầu không đòi hỏi của tôi, nhưng cũng có thể thiên vị theo một cách nào đó.

+0

Điều này trông giống như Objective-C hơn pure-C. –

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