Czy jest funkcja generowania losowej liczby całkowitej w C? Czy będę musiał korzystać z biblioteki strony trzeciej?
srand
: po co dzwonić tylko raz .
Czy jest funkcja generowania losowej liczby całkowitej w C? Czy będę musiał korzystać z biblioteki strony trzeciej?
srand
: po co dzwonić tylko raz .
Odpowiedzi:
Uwaga : Nie używaj
rand()
dla bezpieczeństwa. Jeśli potrzebujesz numeru zabezpieczonego kryptograficznie, zapoznaj się z tą odpowiedzią .
#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.
Edycja : w systemie Linux możesz preferować losowe i losowe .
time()
zmienia się tylko raz na sekundę. Jeśli zaczniesz od time()
, dla każdego połączenia do rand()
, otrzymasz tę samą wartość dla każdego połączenia w ciągu jednej sekundy. Ale głównym powodem jest to, że właściwości rand()
i funkcje tego rodzaju są najlepiej znane w przypadku użycia, w którym są one inicjowane dokładnie raz na uruchomienie, a nie przy każdym wywołaniu. W zależności od „losowości” z niesprawdzonymi lub niesprawdzonymi właściwościami prowadzi do problemów.
rand()
zwykle jest) zaszczepienie przy pomocy rand()
w najlepszym wypadku nie miałoby żadnego efektu, aw najgorszym przypadku złamałoby znane cechy generatora. To głęboki temat. Zacznij od przeczytania Knuth Vol 2 Rozdział 3 o liczbach losowych jako najlepszego wprowadzenia do matematyki i pułapek.
srand((unsigned int)time(NULL));
rand()
Działają w <stdlib.h>
Zwraca pseudo losową liczbę całkowitą między 0 a RAND_MAX
. Możesz użyć, srand(unsigned int seed)
aby ustawić ziarno.
Powszechną praktyką jest używanie %
operatora w połączeniu z, rand()
aby uzyskać inny zasięg (choć należy pamiętać, że to nieco obniża jednolitość). Na przykład:
/* random int between 0 and 19 */
int r = rand() % 20;
Jeśli naprawdę zależy Ci na jednolitości, możesz zrobić coś takiego:
/* 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;
}
}
%
to operator modułu. Daje ci resztę podziału na liczby całkowite, więc x % n
zawsze da ci liczbę pomiędzy 0
i n - 1
(o ilex
i n
są zarówno pozytywne). Jeśli nadal uważasz to za mylące, spróbuj napisać program, który i
liczy od 0 do 100, i wydrukuje i % n
dla niektórych n
wybranych mniejszych niż 100.
Jak rozwiązano w kwestii bezpiecznego generowania liczb losowych w różnych językach programowania , należy wykonać jedną z następujących czynności:
randombytes
API/dev/urandom
, a nie /dev/random
. Nie OpenSSL (lub inne PRNG w przestrzeni użytkownika).Na przykład:
#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()
jest kryptograficznie bezpieczny i bezstronny.
sodium_init()
w pewnym momencie. Nie martw się o RNG, używa jądra.
sodium_init()
chociaż niekoniecznie jest to część mojego przykładu, ponieważ jest to ważny szczegół.
Przejdźmy przez to. Najpierw używamy funkcji srand () do inicjowania randomizatora. Zasadniczo komputer może generować losowe liczby na podstawie liczby podawanej do srand (). Jeśli podasz tę samą wartość początkową, za każdym razem będą generowane te same liczby losowe.
Dlatego musimy zaszczepić randomizator wartością, która zawsze się zmienia. Robimy to, podając mu wartość bieżącego czasu za pomocą funkcji time ().
Teraz, gdy wywołamy rand (), za każdym razem będzie generowany nowy losowy numer.
#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) kończy się niepowodzeniem, kiedy hi_num - low_num > INT_MAX
. 3) Pomija wartości w rzadkiej sytuacji INT_MAX > hi_num - low_num > RAND_MAX
.
hi_num = max_num + 1;
brak ochrony przed przepełnieniem.
Jeśli potrzebujesz pseudolosowych liczb lepszej jakości niż to stdlib
, co oferuje, sprawdź Mersenne Twister . Jest też szybszy. Przykładowe wdrożenia są obfite, na przykład tutaj .
Standardowa funkcja C to rand()
. Wystarczająco dobrze jest rozdawać karty w pasjansa, ale jest okropny. Wiele implementacji rand()
cyklu poprzez krótką listę liczb, a małe bity mają krótsze cykle. Sposób, w jaki niektóre programy wywołują, rand()
jest okropny, a obliczenie dobrego ziarna do przekazania srand()
jest trudne.
Najlepszym sposobem na generowanie liczb losowych w C jest użycie biblioteki innej firmy, takiej jak OpenSSL. Na przykład,
#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;
}
Dlaczego tyle kodu? Inne języki, takie jak Java i Ruby, mają funkcje losowych liczb całkowitych lub liczb zmiennoprzecinkowych. OpenSSL podaje tylko losowe bajty, więc staram się naśladować, w jaki sposób Java lub Ruby przekształciłyby je w liczby całkowite lub zmiennoprzecinkowe.
W przypadku liczb całkowitych chcemy uniknąć błędu modulo . Załóżmy, że otrzymaliśmy losowe 4-cyfrowe liczby całkowite rand() % 10000
, ale rand()
możemy zwrócić tylko 0 do 32767 (jak ma to miejsce w systemie Microsoft Windows). Każda liczba od 0 do 2767 pojawiałaby się częściej niż każda liczba od 2768 do 9999. Aby usunąć błąd, możemy spróbować ponownierand()
gdy wartość jest mniejsza niż 2768, ponieważ wartości 30000 od 2768 do 32767 odwzorowują jednolicie na wartości 10000 od 0 do 9999.
W przypadku liczb zmiennoprzecinkowych chcemy 53 losowe bity, ponieważ double
zawierają 53 bity precyzji (zakładając, że jest to podwójna liczba IEEE). Jeśli użyjemy więcej niż 53 bity, otrzymujemy błąd zaokrąglania. Niektórzy programiści piszą kod podobny rand() / (double)RAND_MAX
, ale rand()
mogą zwrócić tylko 31 bitów lub tylko 15 bitów w systemie Windows.
RAND_bytes()
Ziarna OpenSSL same w sobie, być może poprzez czytanie /dev/urandom
w Linuksie. Jeśli potrzebujemy wielu liczb losowych, odczytanie ich wszystkich byłoby zbyt wolne /dev/urandom
, ponieważ należy je skopiować z jądra. Szybciej pozwala OpenSSL generować więcej liczb losowych z nasion.
Więcej informacji o liczbach losowych:
srand()
. Miksuje bity z bieżącego czasu, identyfikatora procesu i niektórych wskaźników, jeśli nie może odczytać /dev/urandom
.float
/ double
, więc już wyjaśniono kwestię trzymać się int
liczb, aby uniknąć zbyt szerokie. Istnieją inne pytania C zajmujące konkretnie float
/ double
losowych wartości, więc może chcesz odśwież swoją drugą połowę swojej odpowiedzi na pytania takie jak stackoverflow.com/questions/13408990/...
Jeśli twój system obsługuje arc4random
rodzinę funkcji, polecam korzystanie z nich zamiast rand
funkcji standardowej .
arc4random
Rodzina obejmuje:
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
zwraca losową 32-bitową liczbę całkowitą bez znaku.
arc4random_buf
umieszcza losową zawartość w swoim parametrze buf : void *
. Ilość treści zależy od bytes : size_t
parametru.
arc4random_uniform
zwraca losową 32-bitową liczbę całkowitą bez znaku, która jest zgodna z regułą: 0 <= arc4random_uniform(limit) < limit
gdzie limit jest również 32-bitową liczbą całkowitą bez znaku.
arc4random_stir
odczytuje dane /dev/urandom
i przekazuje je, arc4random_addrandom
aby dodatkowo randomizować wewnętrzną pulę liczb losowych.
arc4random_addrandom
służy arc4random_stir
do wypełnienia wewnętrznej puli liczb losowych zgodnie z przekazanymi do niej danymi.
Jeśli nie masz tych funkcji, ale korzystasz z Uniksa, możesz użyć tego kodu:
/* 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;
}
urandom_init
Funkcja otwiera /dev/urandom
urządzenie i umieszcza deskryptor pliku w urandom_fd
.
urandom
Funkcja jest w zasadzie taka sama jak wywołania rand
, z wyjątkiem bardziej bezpieczny, a to zwraca long
(łatwo zmienić).
Jednak /dev/urandom
może być trochę powolny, dlatego zaleca się, aby użyć go jako źródła dla innego generatora liczb losowych.
Jeśli system nie posiada /dev/urandom
, ale nie ma /dev/random
pliku lub podobnego, wtedy można po prostu zmienić ścieżkę przekazanej open
w urandom_init
. Połączenia i API wykorzystywane w urandom_init
i urandom
są (wierzę) POSIX, i jako taki powinien działać na większości, jeśli nie we wszystkich systemach zgodnych z POSIX.
Uwagi: Odczyt /dev/urandom
NIE zablokuje się, jeśli dostępna jest niewystarczająca entropia, więc wartości generowane w takich okolicznościach mogą być niepewne kryptograficznie. Jeśli martwisz się tym, użyj /dev/random
, który zawsze będzie blokował, jeśli nie będzie wystarczającej entropii.
Jeśli korzystasz z innego systemu (np. Windows), użyj rand
lub jakiegoś wewnętrznego, zależnego od platformy, nieprzenośnego interfejsu API.
Wrapper funkcji dla urandom
, rand
, lub arc4random
połączeń:
#define RAND_IMPL /* urandom(see large code block) | rand | arc4random */
int myRandom(int bottom, int top){
return (RAND_IMPL() % (top - bottom)) + bottom;
}
STL nie istnieje dla C. Musisz zadzwonić rand
lub jeszcze lepiej random
. Są one zadeklarowane w standardowym nagłówku biblioteki stdlib.h
. rand
jest POSIX, random
jest funkcją specyfikacji BSD.
Różnica między rand
i random
polega na tym, że random
zwraca o wiele bardziej użyteczną 32-bitową liczbę losową i rand
zwykle zwraca liczbę 16-bitową. Strony BSD pokazują, że niższe bity rand
są cykliczne i przewidywalne, więc rand
potencjalnie są bezużyteczne dla małych liczb.
extern int rand(void);
i extern void srand(unsigned int);
.
Spójrz na ISAAC (Indirection, Shift, Accumulate, Add, and Count). Jest równomiernie rozmieszczony i ma średnią długość cyklu 2 ^ 8295.
To dobry sposób na uzyskanie losowej liczby między dwiema wybranymi liczbami.
#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));
}
Wyjście za pierwszym razem: 39
Wyjście za drugim razem: 61
Wyjście po raz trzeci: 65
Możesz zmienić wartości randnum
na dowolne liczby, które wybierzesz, i wygeneruje dla ciebie losową liczbę między tymi dwiema liczbami.
Chcesz użyć rand()
. Uwaga ( BARDZO WAŻNE ): pamiętaj, aby ustawić ziarno dla funkcji rand. Jeśli tego nie zrobisz, twoje losowe liczby nie są tak naprawdę losowe . To jest bardzo, bardzo, bardzo ważne. Na szczęście zazwyczaj można użyć kombinacji systemowego timera tykania i daty, aby uzyskać dobry początek.
FWIW, odpowiedź brzmi: tak, istnieje stdlib.h
funkcja o nazwie rand
; ta funkcja jest dostosowana przede wszystkim do prędkości i rozkładu, a nie do nieprzewidywalności. Prawie wszystkie wbudowane losowe funkcje dla różnych języków i frameworków domyślnie korzystają z tej funkcji. Istnieją również „kryptograficzne” generatory liczb losowych, które są znacznie mniej przewidywalne, ale działają znacznie wolniej. Powinny być używane w aplikacjach związanych z bezpieczeństwem.
Mam nadzieję, że jest to nieco bardziej losowe niż zwykłe używanie 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());
}
Cóż, STL to C ++, a nie C, więc nie wiem, czego chcesz. Jeśli jednak chcesz C, dostępne są funkcje rand()
i srand()
:
int rand(void);
void srand(unsigned seed);
Obie są częścią ANSI C. Istnieje również random()
funkcja:
long random(void);
Ale, o ile wiem, random()
nie jest standardem ANSI C. Biblioteka innej firmy może nie być złym pomysłem, ale wszystko zależy od losowości liczby, którą naprawdę musisz wygenerować.
C Program do generowania liczb losowych od 9 do 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);
}
Zasadniczo możemy wygenerować losową liczbę między lowerLimit i upperLimit-1
tj. lowerLimit jest włącznie lub powiedz r ∈ [lowerLimit, upperLimit)
rand()
to najwygodniejszy sposób generowania liczb losowych.
Możesz również złapać losową liczbę z dowolnego serwisu internetowego, takiego jak 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;
}
Na nowoczesnych procesorach x86_64 można używać sprzętowego generatora liczb losowych za pośrednictwem _rdrand64_step()
Przykładowy kod:
#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;
}
Słysząc dobre wyjaśnienie, dlaczego używanie rand()
do generowania równomiernie rozmieszczonych liczb losowych w danym zakresie jest złym pomysłem, postanowiłem rzucić okiem na to, jak wypaczony jest wynik. Mój przypadek testowy polegał na rzucie kostką. Oto kod 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);
}
a oto jego wynik:
$ 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%
Nie wiem, jak jednolite są twoje losowe liczby, ale powyższe wydaje się wystarczająco jednolite dla większości potrzeb.
Edycja: dobrym pomysłem byłoby zainicjowanie PRNG za pomocą czegoś lepszego niż time(NULL)
.
Miałem poważny problem z generatorem liczb pseudolosowych w mojej niedawnej aplikacji: wielokrotnie wywoływałem mój program C za pomocą skryptu pyhonona i użyłem jako źródła następującego kodu:
srand(time(NULL))
Jednak ponieważ:
man srand
);time
za każdym razem zwróci tę samą wartość.Mój program wygenerował tę samą sekwencję liczb. Możesz zrobić 3 rzeczy, aby rozwiązać ten problem:
wymieszaj czas wyjściowy z kilkoma innymi informacjami zmieniającymi się podczas uruchomień (w mojej aplikacji nazwa wyjścia):
srand(time(NULL) | getHashOfString(outputName))
Użyłem djb2 jako mojej funkcji skrótu.
Zwiększ rozdzielczość czasową. Na mojej platformie clock_gettime
był dostępny, więc go używam:
#include<time.h>
struct timespec nanos;
clock_gettime(CLOCK_MONOTONIC, &nanos)
srand(nanos.tv_nsec);
Użyj obu metod razem:
#include<time.h>
struct timespec nanos;
clock_gettime(CLOCK_MONOTONIC, &nanos)
srand(nanos.tv_nsec | getHashOfString(outputName));
Opcja 3 zapewnia (o ile mi wiadomo) najlepszą losowość nasion, ale może stworzyć różnicę tylko przy bardzo szybkiej aplikacji. Moim zdaniem opcja 2 to bezpieczny zakład.
rand()
nie należy używać do danych kryptograficznych, zgadzam się. Przynajmniej dla mnie moja aplikacja nie zawierała danych kryptograficznych, więc dla mnie była w porządku podana metoda.
Pomimo wszystkich sugestii ludzi rand()
, nie chcesz używać, rand()
chyba że musisz! Liczby losowe, które rand()
produkują, są często bardzo złe. Cytując ze strony podręcznika systemu Linux:
Wersje
rand()
iwsrand()
bibliotece Linux C Library używają tego samego generatora liczb losowych corandom(3)
israndom(3)
, więc bity niższego rzędu powinny być tak losowe jak bity wyższego rzędu. Jednak w starszych implementacjach rand () i bieżących implementacjach w różnych systemach bity niższego rzędu są znacznie mniej losowe niż bity wyższego rzędu . Nie używaj tej funkcji w aplikacjach, które mają być przenośne, gdy potrzebna jest dobra losowość. ( Zamiast tego użyjrandom(3)
. )
Jeśli chodzi o przenośność, random()
od dłuższego czasu jest również definiowany przez standard POSIX. rand()
jest starszy, pojawił się już w pierwszej specyfikacji POSIX.1 (IEEE Std 1003.1-1988), podczas gdy random()
po raz pierwszy pojawił się w POSIX.1-2001 (IEEE Std 1003.1-2001), ale obecny standard POSIX to już POSIX.1-2008 (IEEE Std 1003.1-2008), który otrzymał aktualizację zaledwie rok temu (IEEE Std 1003.1-2008, edycja 2016). Uważałbym więc, że random()
jest bardzo przenośny.
POSIX.1-2001 wprowadził także funkcje lrand48()
i mrand48()
, patrz tutaj :
Ta rodzina funkcji generuje liczby pseudolosowe przy użyciu liniowego algorytmu kongruencjalnego i 48-bitowej arytmetyki liczb całkowitych.
I całkiem dobrym pseudolosowym źródłem jest arc4random()
funkcja dostępna w wielu systemach. Nie jest częścią żadnego oficjalnego standardu, pojawił się w BSD około 1997 roku, ale można go znaleźć w systemach takich jak Linux i macOS / iOS.
random()
nie istnieje w systemie Windows.
rand()
funkcje, które są wymagane przez standard C. Do wszystkiego innego potrzebujesz specjalnego rozwiązania tylko dla systemu Windows, tak jak zwykle. #ifdef _WIN32
to fraza, którą najczęściej widzisz w kodzie wieloplatformowym, który chce obsługiwać system Windows, a zwykle jest jedno rozwiązanie, które działa ze wszystkimi systemami i jedno, które jest wymagane tylko dla systemu Windows.
W przypadku aplikacji Linux C:
To jest mój przerobiony kod z powyższej odpowiedzi, która jest zgodna z moimi praktykami kodu C i zwraca losowy bufor dowolnej wielkości (z odpowiednimi kodami powrotu itp.). Pamiętaj, aby zadzwonić urandom_open()
raz na początku programu.
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;
}
}
Moje minimalistyczne rozwiązanie powinno działać dla liczb losowych w zakresie [min, max)
. Użyj srand(time(NULL))
przed wywołaniem funkcji.
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));
}
Wypróbuj to, zestawiłem to z niektórych pojęć, o których już wspomniałem powyżej:
/*
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()
każdym razem, gdy chcesz zadzwonić, rand()
to straszny pomysł. Ponieważ time()
zwykle zwraca wartość w sekundach, wywołanie tej funkcji szybko zwróci tę samą „losową” wartość.
random()
funkcją Unixa .