Có một hàm để tạo một số int ngẫu nhiên trong C không? Hay tôi sẽ phải sử dụng thư viện của bên thứ ba?
srand
: tại sao gọi nó chỉ một lần .
Có một hàm để tạo một số int ngẫu nhiên trong C không? Hay tôi sẽ phải sử dụng thư viện của bên thứ ba?
srand
: tại sao gọi nó chỉ một lần .
Câu trả lời:
Lưu ý : Không sử dụng
rand()
để bảo mật. Nếu bạn cần một số bảo mật bằng mật mã, thay vào đó hãy xem câu trả lời này .
#include <time.h>
#include <stdlib.h>
srand(time(NULL)); // Initialization, should only be called once.
int r = rand(); // Returns a pseudo-random integer between 0 and RAND_MAX.
Chỉnh sửa : Trên Linux, bạn có thể thích sử dụng ngẫu nhiên và ngẫu nhiên .
time()
chỉ thay đổi một lần mỗi giây. Nếu bạn chọn từ time()
, cho mỗi cuộc gọi đến rand()
, thì bạn sẽ nhận được cùng một giá trị cho mỗi cuộc gọi trong một giây. Nhưng lý do lớn hơn là các thuộc tính rand()
và chức năng như nó được biết đến tốt nhất cho trường hợp sử dụng khi chúng được gieo chính xác một lần mỗi lần chạy, và không phải trên mỗi cuộc gọi. Tùy thuộc vào "tính ngẫu nhiên" với các thuộc tính chưa được kiểm tra hoặc chưa được chứng minh dẫn đến rắc rối.
rand()
thường là như vậy), việc gieo hạt rand()
tốt nhất sẽ không có tác dụng gì cả, và tệ nhất là sẽ phá vỡ phẩm chất đã biết của máy phát. Đây là một chủ đề sâu sắc. Bắt đầu với việc đọc Knuth Vol 2 Chương 3 về các số ngẫu nhiên là phần giới thiệu tốt nhất về toán học và cạm bẫy.
srand((unsigned int)time(NULL));
Các rand()
chức năng trong <stdlib.h>
lợi nhuận một số nguyên giả ngẫu nhiên giữa 0 và RAND_MAX
. Bạn có thể sử dụng srand(unsigned int seed)
để đặt hạt giống.
Đó là cách phổ biến để sử dụng %
toán tử kết hợp với rand()
để có được một phạm vi khác (mặc dù hãy nhớ rằng điều này sẽ loại bỏ tính đồng nhất một chút). Ví dụ:
/* random int between 0 and 19 */
int r = rand() % 20;
Nếu bạn thực sự quan tâm đến tính đồng nhất, bạn có thể làm một cái gì đó như thế này:
/* Returns an integer in the range [0, n).
*
* Uses rand(), and so is affected-by/affects the same seed.
*/
int randint(int n) {
if ((n - 1) == RAND_MAX) {
return rand();
} else {
// Supporting larger values for n would requires an even more
// elaborate implementation that combines multiple calls to rand()
assert (n <= RAND_MAX)
// Chop off all of the values that would cause skew...
int end = RAND_MAX / n; // truncate skew
assert (end > 0);
end *= n;
// ... and ignore results from rand() that fall above that limit.
// (Worst case the loop condition should succeed 50% of the time,
// so we can expect to bail out of this loop pretty quickly.)
int r;
while ((r = rand()) >= end);
return r % n;
}
}
%
là toán tử mô đun. Nó cung cấp cho bạn phần còn lại của một phép chia số nguyên, vì vậy x % n
sẽ luôn luôn cung cấp cho bạn một số từ 0
và n - 1
(càng lâu càng x
và n
đều dương). Nếu bạn vẫn thấy khó hiểu, hãy thử viết một chương trình có i
số lượng từ 0 đến 100 và in ra i % n
cho một số n
lựa chọn của bạn nhỏ hơn 100.
Như đã đề cập trong cách tạo số ngẫu nhiên một cách an toàn bằng nhiều ngôn ngữ lập trình khác nhau , bạn sẽ muốn thực hiện một trong những điều sau đây:
randombytes
/dev/urandom
, không /dev/random
. Không phải OpenSSL (hoặc PRNG không gian người dùng khác).Ví dụ:
#include "sodium.h"
int foo()
{
char myString[32];
uint32_t myInt;
if (sodium_init() < 0) {
/* panic! the library couldn't be initialized, it is not safe to use */
return 1;
}
/* myString will be an array of 32 random bytes, not null-terminated */
randombytes_buf(myString, 32);
/* myInt will be a random number between 0 and 9 */
myInt = randombytes_uniform(10);
}
randombytes_uniform()
là mật mã an toàn và không thiên vị.
sodium_init()
tại một số điểm. Đừng lo lắng về RNG, nó sử dụng kernel.
sodium_init()
mặc dù nó không nhất thiết là một phần trong ví dụ của tôi vì đó là một chi tiết quan trọng.
Hãy đi qua đây. Đầu tiên chúng ta sử dụng hàm srand () để tạo hạt ngẫu nhiên. Về cơ bản, máy tính có thể tạo các số ngẫu nhiên dựa trên số được đưa vào srand (). Nếu bạn đã cho cùng một giá trị hạt giống, thì các số ngẫu nhiên tương tự sẽ được tạo ra mỗi lần.
Do đó, chúng ta phải chọn hạt ngẫu nhiên với giá trị luôn thay đổi. Chúng tôi làm điều này bằng cách cung cấp cho nó giá trị của thời gian hiện tại với hàm time ().
Bây giờ, khi chúng ta gọi rand (), một số ngẫu nhiên mới sẽ được tạo ra mỗi lần.
#include <stdio.h>
int random_number(int min_num, int max_num);
int main(void)
{
printf("Min : 1 Max : 40 %d\n", random_number(1,40));
printf("Min : 100 Max : 1000 %d\n",random_number(100,1000));
return 0;
}
int random_number(int min_num, int max_num)
{
int result = 0, low_num = 0, hi_num = 0;
if (min_num < max_num)
{
low_num = min_num;
hi_num = max_num + 1; // include max_num in output
} else {
low_num = max_num + 1; // include max_num in output
hi_num = min_num;
}
srand(time(NULL));
result = (rand() % (hi_num - low_num)) + low_num;
return result;
}
else{ low_num=max_num; hi_num=min_num+1;
2) thất bại khi hi_num - low_num > INT_MAX
. 3) Bỏ qua các giá trị trong tình huống hiếm INT_MAX > hi_num - low_num > RAND_MAX
.
hi_num = max_num + 1;
thiếu bảo vệ chống tràn.
Nếu bạn cần số ngẫu nhiên giả chất lượng tốt hơn những gì stdlib
cung cấp, hãy xem Mersenne Twister . Nó cũng nhanh hơn. Mẫu triển khai rất phong phú, ví dụ ở đây .
Hàm C tiêu chuẩn là rand()
. Nó đủ tốt để xử lý thẻ cho trò chơi bài, nhưng thật tệ. Nhiều triển khai rand()
chu kỳ thông qua một danh sách ngắn các số và các bit thấp có chu kỳ ngắn hơn. Cách mà một số chương trình gọi rand()
là khủng khiếp và tính toán một hạt giống tốt để vượt qua srand()
thật khó khăn.
Cách tốt nhất để tạo số ngẫu nhiên trong C là sử dụng thư viện của bên thứ ba như OpenSSL. Ví dụ,
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/rand.h>
/* Random integer in [0, limit) */
unsigned int random_uint(unsigned int limit) {
union {
unsigned int i;
unsigned char c[sizeof(unsigned int)];
} u;
do {
if (!RAND_bytes(u.c, sizeof(u.c))) {
fprintf(stderr, "Can't get random bytes!\n");
exit(1);
}
} while (u.i < (-limit % limit)); /* u.i < (2**size % limit) */
return u.i % limit;
}
/* Random double in [0.0, 1.0) */
double random_double() {
union {
uint64_t i;
unsigned char c[sizeof(uint64_t)];
} u;
if (!RAND_bytes(u.c, sizeof(u.c))) {
fprintf(stderr, "Can't get random bytes!\n");
exit(1);
}
/* 53 bits / 2**53 */
return (u.i >> 11) * (1.0/9007199254740992.0);
}
int main() {
printf("Dice: %d\n", (int)(random_uint(6) + 1));
printf("Double: %f\n", random_double());
return 0;
}
Tại sao nhiều mã? Các ngôn ngữ khác như Java và Ruby có các hàm cho số nguyên hoặc số float ngẫu nhiên. OpenSSL chỉ cung cấp các byte ngẫu nhiên, vì vậy tôi cố gắng bắt chước cách Java hoặc Ruby biến đổi chúng thành số nguyên hoặc số float.
Đối với số nguyên, chúng tôi muốn tránh sai lệch modulo . Giả sử rằng chúng tôi đã nhận được một số số nguyên 4 chữ số ngẫu nhiên từ rand() % 10000
, nhưng rand()
chỉ có thể trả về 0 đến 32767 (giống như trong Microsoft Windows). Mỗi số từ 0 đến 2767 sẽ xuất hiện thường xuyên hơn mỗi số từ 2768 đến 9999. Để xóa sai lệch, chúng tôi có thể thử lại rand()
trong khi giá trị dưới 2768, vì 30000 giá trị từ 2768 đến 32767 ánh xạ đồng nhất vào 10000 giá trị từ 0 đến 9999.
Đối với số float, chúng tôi muốn có 53 bit ngẫu nhiên, bởi vì double
độ chính xác giữ 53 bit (giả sử đó là gấp đôi của IEEE). Nếu chúng ta sử dụng nhiều hơn 53 bit, chúng ta sẽ có độ lệch làm tròn. Một số lập trình viên viết mã như thế rand() / (double)RAND_MAX
, nhưng rand()
có thể chỉ trả về 31 bit hoặc chỉ 15 bit trong Windows.
RAND_bytes()
Hạt giống của OpenSSL , có lẽ bằng cách đọc /dev/urandom
trong Linux. Nếu chúng ta cần nhiều số ngẫu nhiên, sẽ quá chậm để đọc tất cả chúng /dev/urandom
, bởi vì chúng phải được sao chép từ kernel. Sẽ nhanh hơn khi cho phép OpenSSL tạo ra nhiều số ngẫu nhiên hơn từ một hạt giống.
Thông tin thêm về các số ngẫu nhiên:
srand()
. Nó trộn các bit từ thời điểm hiện tại, ID tiến trình và một số con trỏ, nếu không thể đọc được /dev/urandom
.float
/ double
, vì vậy tôi đã làm rõ câu hỏi để bám vào các int
con số để tránh làm cho nó quá rộng. Có những câu hỏi C khác liên quan cụ thể đếnfloat
/ double
giá trị ngẫu nhiên, vì vậy bạn có thể muốn đăng lại nửa sau câu trả lời của mình cho các câu hỏi như stackoverflow.com/questions/13408990/
Nếu hệ thống của bạn hỗ trợ arc4random
họ các chức năng, tôi sẽ khuyên bạn nên sử dụng các rand
chức năng thay vì chức năng tiêu chuẩn .
Các arc4random
gia đình bao gồm:
uint32_t arc4random(void)
void arc4random_buf(void *buf, size_t bytes)
uint32_t arc4random_uniform(uint32_t limit)
void arc4random_stir(void)
void arc4random_addrandom(unsigned char *dat, int datlen)
arc4random
trả về một số nguyên không dấu 32 bit ngẫu nhiên.
arc4random_buf
đặt nội dung ngẫu nhiên trong tham số của nó buf : void *
. Số lượng nội dung được xác định bởi bytes : size_t
tham số.
arc4random_uniform
trả về một số nguyên không dấu 32 bit ngẫu nhiên theo quy tắc : 0 <= arc4random_uniform(limit) < limit
, trong đó giới hạn cũng là một số nguyên 32 bit không dấu.
arc4random_stir
đọc dữ liệu từ /dev/urandom
và chuyển dữ liệu sang arc4random_addrandom
ngẫu nhiên thêm nhóm số ngẫu nhiên nội bộ của nó.
arc4random_addrandom
được sử dụng arc4random_stir
để điền vào nhóm số ngẫu nhiên nội bộ của nó theo dữ liệu được truyền cho nó.
Nếu bạn không có các chức năng này, nhưng bạn đang ở trên Unix, thì bạn có thể sử dụng mã này:
/* This is C, not C++ */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h> /* exit */
#include <stdio.h> /* printf */
int urandom_fd = -2;
void urandom_init() {
urandom_fd = open("/dev/urandom", O_RDONLY);
if (urandom_fd == -1) {
int errsv = urandom_fd;
printf("Error opening [/dev/urandom]: %i\n", errsv);
exit(1);
}
}
unsigned long urandom() {
unsigned long buf_impl;
unsigned long *buf = &buf_impl;
if (urandom_fd == -2) {
urandom_init();
}
/* Read 4 bytes, or 32 bits into *buf, which points to buf_impl */
read(urandom_fd, buf, sizeof(long));
return buf_impl;
}
Các urandom_init
chức năng mở /dev/urandom
thiết bị, và đặt các bộ mô tả tập tin trong urandom_fd
.
Các urandom
chức năng cơ bản là giống như một cuộc gọi đến rand
, ngoại trừ an toàn hơn, và nó trả về một long
(dễ dàng thay đổi).
Tuy nhiên, /dev/urandom
có thể hơi chậm, vì vậy bạn nên sử dụng nó làm hạt giống cho một trình tạo số ngẫu nhiên khác nhau.
Nếu hệ thống của bạn không có một /dev/urandom
, nhưng không có một /dev/random
hoặc tập tin tương tự, sau đó bạn chỉ có thể thay đổi đường dẫn truyền cho open
trong urandom_init
. Các cuộc gọi và API được sử dụng trongurandom_init
và urandom
(tôi tin) tuân thủ POSIX và như vậy, sẽ hoạt động trên hầu hết, nếu không phải tất cả các hệ thống tuân thủ POSIX.
Ghi chú: Đọc từ /dev/urandom
sẽ KHÔNG chặn nếu không có đủ entropy, do đó, các giá trị được tạo trong các trường hợp như vậy có thể không an toàn về mặt mật mã. Nếu bạn lo lắng về điều đó, thì hãy sử dụng /dev/random
, nó sẽ luôn chặn nếu không có đủ entropy.
Nếu bạn đang ở trên một hệ thống khác (tức là Windows), thì hãy sử dụng rand
hoặc một số API không di động phụ thuộc vào nền tảng cụ thể của Windows.
Wrapper chức năng cho urandom
, rand
hoặc arc4random
cuộc gọi:
#define RAND_IMPL /* urandom(see large code block) | rand | arc4random */
int myRandom(int bottom, int top){
return (RAND_IMPL() % (top - bottom)) + bottom;
}
STL không tồn tại cho C. Bạn phải gọi rand
, hoặc tốt hơn , random
. Chúng được khai báo trong tiêu đề thư viện tiêu chuẩn stdlib.h
. rand
là POSIX, random
là một chức năng đặc tả BSD.
Sự khác biệt giữa rand
và random
là random
trả về số ngẫu nhiên 32 bit có thể sử dụng nhiều hơn và rand
thường trả về số 16 bit. Các trang web BSD cho thấy các bit thấp hơn rand
có chu kỳ và có thể dự đoán được, do đó rand
có khả năng vô dụng đối với số lượng nhỏ.
extern int rand(void);
và extern void srand(unsigned int);
.
Có một cái nhìn về ISAAC (Indirection, Shift, Accumulation, Add và Count). Nó phân bố đồng đều và có chiều dài chu kỳ trung bình là 2 ^ 8295.
Đây là một cách tốt để có được một số ngẫu nhiên giữa hai số bạn chọn.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define randnum(min, max) \
((rand() % (int)(((max) + 1) - (min))) + (min))
int main()
{
srand(time(NULL));
printf("%d\n", randnum(1, 70));
}
Đầu ra lần đầu tiên: 39
Đầu ra lần thứ hai: 61
Đầu ra lần thứ ba: 65
Bạn có thể thay đổi các giá trị sau randnum
thành bất kỳ số nào bạn chọn và nó sẽ tạo ra một số ngẫu nhiên cho bạn giữa hai số đó.
Bạn muốn sử dụng rand()
. Lưu ý ( RẤT QUAN TRỌNG ): đảm bảo đặt hạt giống cho chức năng rand. Nếu bạn không, số ngẫu nhiên của bạn không thực sự ngẫu nhiên . Điều này rất, rất, rất quan trọng. Rất may, bạn thường có thể sử dụng một số kết hợp của bộ đếm thời gian đánh dấu hệ thống và ngày để có được một hạt giống tốt.
FWIW, câu trả lời là có, có một stdlib.h
hàm được gọi rand
; chức năng này được điều chỉnh chủ yếu cho tốc độ và phân phối, không phải là không thể đoán trước. Hầu như tất cả các hàm ngẫu nhiên tích hợp cho các ngôn ngữ và khung khác nhau đều sử dụng chức năng này theo mặc định. Ngoài ra còn có các trình tạo số ngẫu nhiên "mật mã" ít được dự đoán hơn, nhưng chạy chậm hơn nhiều. Chúng nên được sử dụng trong bất kỳ loại ứng dụng nào liên quan đến bảo mật.
Điều này hy vọng sẽ ngẫu nhiên hơn một chút so với việc chỉ sử dụng srand(time(NULL))
.
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
srand((unsigned int)**main + (unsigned int)&argc + (unsigned int)time(NULL));
srand(rand());
for (int i = 0; i < 10; i++)
printf("%d\n", rand());
}
Chà, STL là C ++, không phải C, vì vậy tôi không biết bạn muốn gì. Nếu bạn muốn C, tuy nhiên, có rand()
và các srand()
hàm:
int rand(void);
void srand(unsigned seed);
Cả hai đều là một phần của ANSI C. Ngoài ra còn có random()
chức năng:
long random(void);
Nhưng theo như tôi có thể nói, random()
không phải là ANSI tiêu chuẩn C. Thư viện của bên thứ ba có thể không phải là ý tưởng tồi, nhưng tất cả phụ thuộc vào mức độ ngẫu nhiên của một số bạn thực sự cần tạo.
Chương trình C để tạo số ngẫu nhiên từ 9 đến 50
#include <time.h>
#include <stdlib.h>
int main()
{
srand(time(NULL));
int lowerLimit = 10, upperLimit = 50;
int r = lowerLimit + rand() % (upperLimit - lowerLimit);
printf("%d", r);
}
Nói chung, chúng ta có thể tạo một số ngẫu nhiên giữa lowLimit và UpperLimit-1
tức là lowLimit được bao gồm hoặc nói r ∈ [lowLimit, UpperLimit)
rand()
là cách thuận tiện nhất để tạo số ngẫu nhiên.
Bạn cũng có thể bắt số ngẫu nhiên từ bất kỳ dịch vụ trực tuyến nào như Random.org.
#include <stdio.h>
#include <stdlib.h>
void main()
{
int visited[100];
int randValue, a, b, vindex = 0;
randValue = (rand() % 100) + 1;
while (vindex < 100) {
for (b = 0; b < vindex; b++) {
if (visited[b] == randValue) {
randValue = (rand() % 100) + 1;
b = 0;
}
}
visited[vindex++] = randValue;
}
for (a = 0; a < 100; a++)
printf("%d ", visited[a]);
}
#include <stdio.h>
#include <dos.h>
int random(int range);
int main(void)
{
printf("%d", random(10));
return 0;
}
int random(int range)
{
struct time t;
int r;
gettime(&t);
r = t.ti_sec % range;
return r;
}
Trên các CPU x86_64 hiện đại, bạn có thể sử dụng trình tạo số ngẫu nhiên phần cứng thông qua _rdrand64_step()
Mã ví dụ:
#include <immintrin.h>
uint64_t randVal;
if(!_rdrand64_step(&randVal)) {
// Report an error here: random number generation has failed!
}
// If no error occured, randVal contains a random 64-bit number
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//generate number in range [min,max)
int random(int min, int max){
int number = min + rand() % (max - min);
return number;
}
//Driver code
int main(){
srand(time(NULL));
for(int i = 1; i <= 10; i++){
printf("%d\t", random(10, 100));
}
return 0;
}
Nghe một lời giải thích tốt về lý do tại sao sử dụng rand()
để tạo ra các số ngẫu nhiên phân bố đồng đều trong một phạm vi nhất định là một ý tưởng tồi, tôi quyết định xem xét mức độ sai lệch của đầu ra thực sự. Trường hợp thử nghiệm của tôi là ném xúc xắc công bằng. Đây là mã C:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i;
int dice[6];
for (i = 0; i < 6; i++)
dice[i] = 0;
srand(time(NULL));
const int TOTAL = 10000000;
for (i = 0; i < TOTAL; i++)
dice[(rand() % 6)] += 1;
double pers = 0.0, tpers = 0.0;
for (i = 0; i < 6; i++) {
pers = (dice[i] * 100.0) / TOTAL;
printf("\t%1d %5.2f%%\n", dice[i], pers);
tpers += pers;
}
printf("\ttotal: %6.2f%%\n", tpers);
}
và đây là đầu ra của nó:
$ gcc -o t3 t3.c
$ ./t3
1666598 16.67%
1668630 16.69%
1667682 16.68%
1666049 16.66%
1665948 16.66%
1665093 16.65%
total: 100.00%
$ ./t3
1667634 16.68%
1665914 16.66%
1665542 16.66%
1667828 16.68%
1663649 16.64%
1669433 16.69%
total: 100.00%
Tôi không biết bạn cần số đồng phục ngẫu nhiên như thế nào, nhưng ở trên có vẻ đồng nhất đủ cho hầu hết các nhu cầu.
Chỉnh sửa: sẽ là một ý tưởng tốt để khởi tạo PRNG với một cái gì đó tốt hơn time(NULL)
.
Tôi đã gặp một vấn đề nghiêm trọng với trình tạo số ngẫu nhiên giả trong ứng dụng gần đây của mình: Tôi đã gọi lại chương trình C của mình thông qua một tập lệnh pyhton và tôi đang sử dụng làm mã giống như sau:
srand(time(NULL))
Tuy nhiên, kể từ:
man srand
);time
sẽ trả về cùng một giá trị mỗi lần.Chương trình của tôi tạo ra chuỗi số tương tự. Bạn có thể làm 3 điều để giải quyết vấn đề này:
trộn thời gian đầu ra với một số thông tin khác thay đổi khi chạy (trong ứng dụng của tôi, tên đầu ra):
srand(time(NULL) | getHashOfString(outputName))
Tôi đã sử dụng djb2 làm hàm băm của mình.
Tăng độ phân giải thời gian. Trên nền tảng của tôi, clock_gettime
đã có sẵn, vì vậy tôi sử dụng nó:
#include<time.h>
struct timespec nanos;
clock_gettime(CLOCK_MONOTONIC, &nanos)
srand(nanos.tv_nsec);
Sử dụng cả hai phương pháp với nhau:
#include<time.h>
struct timespec nanos;
clock_gettime(CLOCK_MONOTONIC, &nanos)
srand(nanos.tv_nsec | getHashOfString(outputName));
Tùy chọn 3 đảm bảo cho bạn (theo như tôi biết) tính ngẫu nhiên hạt giống tốt nhất, nhưng nó có thể tạo ra sự khác biệt chỉ trên ứng dụng rất nhanh. Theo tôi, lựa chọn 2 là đặt cược an toàn.
rand()
Tôi không nên sử dụng dữ liệu mật mã, tôi đồng ý. Ít nhất là đối với tôi, ứng dụng của tôi không liên quan đến dữ liệu mật mã, vì vậy đối với tôi, đó là phương pháp đã cho.
Mặc dù tất cả những người đề nghị rand()
ở đây, bạn không muốn sử dụng rand()
trừ khi bạn phải làm thế! Các số ngẫu nhiên màrand()
tạo ra thường rất xấu. Để trích dẫn từ trang người đàn ông Linux:
Các phiên bản
rand()
vàsrand()
trong Thư viện Linux C sử dụng cùng một trình tạo số ngẫu nhiên nhưrandom(3)
vàsrandom(3)
, do đó, các bit bậc thấp hơn sẽ ngẫu nhiên như các bit bậc cao hơn. Tuy nhiên, trên các triển khai rand () cũ hơn và trên các triển khai hiện tại trên các hệ thống khác nhau, các bit bậc thấp ít ngẫu nhiên hơn nhiều so với các bit bậc cao hơn . Không sử dụng chức năng này trong các ứng dụng dự định có thể mang theo khi cần sự ngẫu nhiên tốt. ( Sử dụngrandom(3)
thay thế. )
Về tính di động, random()
cũng được xác định theo tiêu chuẩn POSIX từ khá lâu. rand()
đã cũ hơn, nó đã xuất hiện trong thông số POSIX.1 đầu tiên (IEEE Std 1003.1-1988), trong khirandom()
lần đầu tiên xuất hiện trong POSIX.1-2001 (IEEE Std 1003.1-2001), nhưng tiêu chuẩn POSIX hiện tại đã là POSIX.1-2008 (IEEE Std 1003.1-2008), đã nhận được bản cập nhật chỉ một năm trước (Phiên bản IEEE Std 1003.1-2008, 2016). Vì vậy tôi sẽ xem xétrandom()
để rất di động.
POSIX.1-2001 cũng đã giới thiệu lrand48()
và các mrand48()
chức năng, xem tại đây :
Họ các hàm này sẽ tạo ra các số giả ngẫu nhiên bằng thuật toán đồng quy tuyến tính và số học số nguyên 48 bit.
Và nguồn ngẫu nhiên giả khá tốt là arc4random()
chức năng có sẵn trên nhiều hệ thống. Không phải là một phần của bất kỳ tiêu chuẩn chính thức nào, xuất hiện trong BSD vào khoảng năm 1997 nhưng bạn có thể tìm thấy nó trên các hệ thống như Linux và macOS / iOS.
random()
không tồn tại trên Windows.
rand()
vì nó cũng được yêu cầu bởi tiêu chuẩn C. Đối với bất cứ điều gì khác, bạn cần một giải pháp đặc biệt chỉ dành cho Windows, giống như bình thường. #ifdef _WIN32
là cụm từ bạn sẽ thấy thường xuyên nhất trong mã đa nền tảng muốn hỗ trợ Windows cũng như thường có một giải pháp hoạt động với tất cả các hệ thống và một giải pháp chỉ dành cho Windows.
Đối với các ứng dụng Linux C:
Đây là mã được làm lại của tôi từ một câu trả lời ở trên tuân theo các thực hành mã C của tôi và trả về một bộ đệm ngẫu nhiên có kích thước bất kỳ (với mã trả về thích hợp, v.v.). Hãy chắc chắn gọi urandom_open()
một lần khi bắt đầu chương trình của bạn.
int gUrandomFd = -1;
int urandom_open(void)
{
if (gUrandomFd == -1) {
gUrandomFd = open("/dev/urandom", O_RDONLY);
}
if (gUrandomFd == -1) {
fprintf(stderr, "Error opening /dev/urandom: errno [%d], strerrer [%s]\n",
errno, strerror(errno));
return -1;
} else {
return 0;
}
}
void urandom_close(void)
{
close(gUrandomFd);
gUrandomFd = -1;
}
//
// This link essentially validates the merits of /dev/urandom:
// http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
//
int getRandomBuffer(uint8_t *buf, int size)
{
int ret = 0; // Return value
if (gUrandomFd == -1) {
fprintf(stderr, "Urandom (/dev/urandom) file not open\n");
return -1;
}
ret = read(gUrandomFd, buf, size);
if (ret != size) {
fprintf(stderr, "Only read [%d] bytes, expected [%d]\n",
ret, size);
return -1;
} else {
return 0;
}
}
Giải pháp tối giản của tôi sẽ làm việc cho các số ngẫu nhiên trong phạm vi [min, max)
. Sử dụng srand(time(NULL))
trước khi gọi hàm.
int range_rand(int min_num, int max_num) {
if (min_num >= max_num) {
fprintf(stderr, "min_num is greater or equal than max_num!\n");
}
return min_num + (rand() % (max_num - min_num));
}
Hãy thử điều này, tôi kết hợp nó từ một số khái niệm đã được tham chiếu ở trên:
/*
Uses the srand() function to seed the random number generator based on time value,
then returns an integer in the range 1 to max. Call this with random(n) where n is an integer, and you get an integer as a return value.
*/
int random(int max) {
srand((unsigned) time(NULL));
return (rand() % max) + 1;
}
srand()
mỗi khi bạn muốn gọi rand()
là một ý tưởng khủng khiếp. Vì time()
thường trả về một giá trị trong vài giây, gọi hàm này một cách nhanh chóng sẽ trả về cùng một giá trị "ngẫu nhiên".
random()
chức năng của Unix .