C rasgele bir int nasıl oluşturulur?


Yanıtlar:


662

Not : rand()Güvenlik için kullanmayın . Kriptografik olarak güvenli bir numaraya ihtiyacınız varsa, bunun yerine bu cevaba bakın .

#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.

Düzenleme : Linux'ta rasgele ve srandom kullanmayı tercih edebilirsiniz .


194
Basitlik için +1, ancak srand () işlevinin yalnızca bir kez çağrılması gerektiğini vurgulamak muhtemelen iyi bir fikirdir . Ayrıca, dişli bir uygulamada, jeneratörün durumunun iplik başına saklandığından emin olmak ve jeneratörü her iplik için bir kez tohumlamak isteyebilirsiniz.
RBerteig

41
@trusktr, karmaşık. İşte bir nedeni: time()Saniyede yalnızca bir kez değişir. Şuradan ayrılırsanız time(), her çağrı için rand()tek bir saniye boyunca her çağrı için aynı değeri alırsınız. Ancak en büyük neden, rand()her bir çağrıda değil, her çalışmada tam olarak bir kez tohumlandıkları kullanım durumu için özelliklerinin ve işlevlerinin en iyi bilinmesidir. Test edilmemiş veya kanıtlanmamış özelliklere sahip "rastgelelik" e bağlı olarak soruna yol açar.
RBerteig

9
@trusktr ile basit bir doğrusal kongruratif jeneratör (ki rand()genellikle budur) tohumlamanın rand()en iyi şekilde hiçbir etkisi olmaz ve en kötü ihtimalle jeneratörün bilinen özelliklerini bozar. Bu derin bir konu. Matematik ve tuzaklara en iyi giriş olarak rastgele sayılar üzerinde Knuth Cilt 2 Bölüm 3'ü okumaya başlayın .
RBerteig

21
Oyuncularla derleyici uyarısından kaçının:srand((unsigned int)time(NULL));
GiovaMaster

9
Bunun PRNG'yi görmenin hala zayıf bir yolu olduğunu unutmayın. Sadece geçen yıl, Linux'ta bir şifreleme türü virüs, zamanla tohumlama hatası yaptı ve bu , arama alanını önemli ölçüde azalttı. Yapmanız gereken tek şey, enfeksiyonun ne zaman meydana geldiğine dair iyi bir fikir edinmek ve daha sonra o zamandan itibaren tohumları denemekti. Son duydum, en iyi rastgelelik kaynağı / dev / urandom, sözde donanımdaki sıcaklıklar gibi kaotik-ish kaynaklarının bir araya getirilmesinden kaynaklanıyor. Bununla birlikte, gerçekten istediğiniz her şey programınızın her çalıştırmada farklı hareket etmesi için yukarıdaki çözüm iyidir.
Jemenake

238

İçindeki rand()işlev <stdlib.h>0 ile arasında bir rasgele rasgele tamsayı döndürür RAND_MAX. Kullanabilirsinizsrand(unsigned int seed)Bir tohum ayarlamak için .

Farklı bir menzil elde etmek için %operatörü birlikte kullanmak yaygın bir uygulamadır rand()(bunun tekdüzeliği bir şekilde attığını unutmayın). Örneğin:

/* random int between 0 and 19 */
int r = rand() % 20;

Eğer varsa gerçekten bütünlüğü umurumda böyle bir şey yapabilirsiniz:

/* 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;
  }
}

18
Bu yaygın bir uygulamadır , fakat doğru değildir. Bkz bu ve bu .
Lazer

35
@Lazer: Bu yüzden "bunun tekdüzeliği bir şekilde attığını aklınızdan çıkarmayın" dedim.
Laurence Gonsalves

3
@AbhimanyuAryan %Modül operatörüdür. Size bir tamsayı bölümünün geri kalanını verir, bu yüzden x % nher zaman 0ve arasında bir sayı verecektir n - 1( xve nher ikisi de pozitif olduğu sürece ). Hala kafa karıştırıcı olduğunu fark ederseniz, bir programı yazmayı deneyin i0 ile 100 sayar, baskılar i % nbazıları için nsenin seçmenin daha küçük 100.
Laurence Gonsalves

2
@necromancer Devam ettim ve mükemmel bir şekilde tek tip bir çözüm ekledim.
Laurence Gonsalves

2
@Lazer, yayınladığınız ikinci bağlantı aslında hala tekdüze değil. Bir çifte ve arkaya yayın yapmak yardımcı olmaz. Gönderdiğiniz ilk bağlantı mükemmel bir düzgün çözüme sahiptir, ancak küçük üst sınırlar için çok fazla döngü yapacaktır . Bu cevaba, küçük üst sınırlar için bile çok fazla döngü oluşturmaması gereken mükemmel düzgün bir çözüm ekledim.
Laurence Gonsalves

53

Güvenli rastgele karakterler veya tamsayılara ihtiyacınız varsa:

Çeşitli programlama dillerinde rasgele sayıların nasıl güvenli bir şekilde oluşturulacağı konusunda ele alındığı gibi , aşağıdakilerden birini yapmak istersiniz:

Örneğin:

#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() kriptografik olarak güvenli ve tarafsızdır.


randombytes_buf çağırmadan önce libsodium RNG tohumlanmalıdır?
user2199593

Sadece bir ara arayın sodium_init(). RNG için endişelenmeyin, çekirdeği kullanır.
Scott Arciszewski

Not: sodium_init()Önemli bir ayrıntı olduğu için örneğimin bir parçası olmamasına rağmen son düzenlemeyi onayladım .
Scott Arciszewski

29

Hadi bunun üzerinden geçelim. İlk önce rasgeleleştiriciyi tohumlamak için srand () işlevini kullanıyoruz. Temel olarak, bilgisayar srand () öğesine beslenen sayıya göre rastgele sayılar üretebilir. Aynı tohum değerini verdiyseniz, her seferinde aynı rastgele sayılar üretilir.

Bu nedenle, randomizörü her zaman değişen bir değerle tohumlamalıyız. Bunu, time () işleviyle geçerli zamanın değerini besleyerek yaparız.

Şimdi, rand () dediğimizde, her seferinde yeni bir rastgele sayı üretilecektir.

#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;
}

12
Güzel Kod, ama 'srand (time (NULL));' demek iyi bir fikir değil. bu yöntem, for döngüsünde çağrıldığında aynı sayıyı üretir.
RayOldProf

1
Kod içeren önerilen düzenlemeler genellikle reddedilir. Birisi burada "algoritma yanlıştı, maksimumdan daha büyük sayılar üretebilir" yorumuyla bir tane yaptı . Talebi kendim değerlendirmedim.
Martin Smith

1
@Martin Smith Problems: 1) olmalıdır else{ low_num=max_num; hi_num=min_num+1;2) ne zaman başarısız olur hi_num - low_num > INT_MAX. 3) Nadir durumlarda değerleri atlar INT_MAX > hi_num - low_num > RAND_MAX.
chux - Monica'yı iade et

1
Aynı şekilde yeniden boyutlandırılması, aynı saniyede birden çok kez çağrılırsa bu işlevin aynı sayıyı üretmesine neden olur. Gerçekten yeniden tohumlamak istiyorsanız, saniyede sadece bir kez yeniden tohumlayın.
Élektra

1
Küçük: hi_num = max_num + 1;taşmaya karşı korumadan yoksundur.
chux - Monica'ya geri dön

25

Sağlananlardan daha kaliteli sahte rasgele sayılara ihtiyacınız varsa stdlib, Mersenne Twister'a göz atın . Aynı zamanda daha hızlı. Örnek uygulamalar çok fazla, örneğin burada .


2
+1: Harika görünüyor ama sadece bir tahmin oyunu yapıyordum. Eğer bir iş uygulamasında rasgele sayı üreteci kullanacak olsaydım, kesinlikle bunu kullanırdım.
Kredns

4
Mersenne Twister kullanmayın, xoroshiro128 + veya PCG gibi iyi bir şey kullanmayın. (İlgili bağlantı.)
Veedrac

17

Standart C işlevi rand(). Solitaire için kart dağıtmak için yeterince iyi, ama korkunç. Birçok uygulama, rand()kısa bir sayı listesinden geçer ve düşük bitler daha kısa döngülere sahiptir. Bazı programların çağırma rand()şekli korkunçtur ve geçmesi için iyi bir tohum hesaplamak srand()zordur.

C'de rastgele sayılar üretmenin en iyi yolu OpenSSL gibi üçüncü taraf bir kitaplık kullanmaktır. Örneğin,

#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;
}

Neden bu kadar kod? Java ve Ruby gibi diğer dillerde rasgele tamsayılar veya kayan noktalar için işlevler bulunur. OpenSSL yalnızca rastgele bayt verir, bu yüzden Java veya Ruby'nin bunları tamsayılara veya kayan noktalara nasıl dönüştüreceğini taklit etmeye çalışırım.

Tamsayılar için, modulo yanlılığından kaçınmak istiyoruz . Diyelim ki bazı rastgele 4 basamaklı tamsayılarımız var rand() % 10000, ancak rand()yalnızca 0 - 32767 (Microsoft Windows'da olduğu gibi) döndürebilir. 0'dan 2767'ye kadar olan her sayı 2768'den 9999'a kadar her sayıdan daha sık görünecektir. Yanlılığı kaldırmak için rand(), değer 2768'in altındayken tekrar deneyebiliriz , çünkü 2768'den 32767'ye kadar 30000 değerleri 0'dan 10000'e eşleştirilir. 9999.

Şamandıralar için 53 rastgele bit istiyoruz, çünkü double53 bitlik hassasiyet (IEEE çift olduğu varsayılarak) var. 53 bitten fazla kullanırsak, yuvarlama sapması elde ederiz. Bazı programcılar gibi kod yazmak rand() / (double)RAND_MAX, ancak rand()Windows'da yalnızca 31 bit veya yalnızca 15 bit döndürebilir.

OpenSSL'nin RAND_bytes()tohumları, belki de /dev/urandomLinux'ta okuyarak . Çok sayıda rastgele sayıya ihtiyacımız varsa, hepsini okumak çok yavaş olurdu /dev/urandom, çünkü çekirdekten kopyalanmaları gerekir. OpenSSL'nin bir tohumdan daha fazla rasgele sayı üretmesine izin vermek daha hızlıdır.

Rasgele sayılar hakkında daha fazla bilgi:


Bu uzatılmış cevap için teşekkür ederim. Bu soruya verilen 24 güncel cevaptan float/ ile başa çıkmak için ekstra bir yorum yapan tek kişi sizsiniz double, bu yüzden soruyu çok genişlememek için intsayılara sadık kalmak için açıkladım . Özellikle float/ doublerastgele değerlerle ilgili başka C soruları da var , bu nedenle stackoverflow.com/questions/13408990/…
Cœur

11

Sisteminiz arc4randomişlev ailesini destekliyorsa, bunun yerine standart randişlevi kullanmanızı öneririm .

arc4randomAile içerir:

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 rastgele bir 32 bit işaretsiz tam sayı döndürür.

arc4random_bufparametresine rastgele içerik koyar buf : void *. İçerik miktarı bytes : size_tparametre tarafından belirlenir .

arc4random_uniformkuralı izleyen rastgele bir 32 bit işaretsiz tam sayı döndürür: 0 <= arc4random_uniform(limit) < limitburada sınır aynı zamanda işaretsiz bir 32 bit tam sayıdır.

arc4random_stirdahili rasgele sayı havuzuna ek olarak rasgele eklenmek /dev/urandomüzere verileri okur ve bu veriye arc4random_addrandomaktarır.

arc4random_addrandomtarafından arc4random_stiraktarılan verilere göre dahili rasgele sayı havuzunu doldurmak için kullanılır .

Bu işlevlere sahip değilseniz, ancak Unix'deyseniz, bu kodu kullanabilirsiniz:

/* 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_initFonksiyon açar /dev/urandomcihazı ve dosya tanımlayıcısı koyar urandom_fd.

urandomFonksiyon temelde bir çağrı aynıdır randdaha güvenli hariç ve bir döner long(kolayca değiştirilebilir).

Bununla birlikte, /dev/urandombiraz yavaş olabilir, bu yüzden farklı bir rastgele sayı üreteci için bir tohum olarak kullanmanız önerilir.

Sisteminiz bir yoksa /dev/urandom, ama yok bir var /dev/randomya da benzeri bir dosya, o zaman sadece geçirilen yolunu değiştirebilir openiçinde urandom_init. POSIX uyumlu urandom_initve kullanılan aramalar ve API'lar urandom, POSIX uyumlu sistemlerin hepsinde olmasa bile çoğunda çalışmalıdır.

Notlar: /dev/urandomYeterli entropi yoksa okuma değeri engellenmez, bu nedenle bu koşullar altında üretilen değerler kriptografik olarak güvensiz olabilir. Bu konuda endişeleriniz varsa, o zaman kullanın /dev/random, yetersiz entropi varsa her zaman engellenir.

Başka bir sistemdeyseniz (örn. Windows), randWindows'a özgü platforma özgü taşınabilir olmayan bir API kullanın.

Fonksiyon için Sarıcı urandom, randya arc4randomaramalar:

#define RAND_IMPL /* urandom(see large code block) | rand | arc4random */

int myRandom(int bottom, int top){
    return (RAND_IMPL() % (top - bottom)) + bottom;
}

8

C için STL mevcut değil. Aramanız randveya daha iyisi random. Bunlar standart kütüphane başlığında bildirilmiştir stdlib.h. randPOSIX, randombir BSD spesifikasyon fonksiyonudur.

Arasındaki fark randve randomolmasıdır randomçok daha kullanışlı bir 32-bit rasgele sayı döner ve randtipik olarak 16 bit sayısını verir. BSD manajları, düşük bitlerin randdöngüsel ve öngörülebilir olduğunu gösterir, bu nedenle randküçük sayılar için potansiyel olarak işe yaramaz.


3
@Neil - Şimdiye kadar tüm cevaplar STL'den bahsettiğinden, sorunun gereksiz referansı kaldırmak için hızlı bir şekilde düzenlendiğinden şüpheleniyorum.
Michael Burr

rand () küçük sayılar için işe yaramaz - onları bitirebilir ve gerçekten ihtiyacınız varsa daha rastgele yüksek bitleri kullanabilirsiniz.
Chris Lutz

@Chris, rastgele sayının boyutu biliniyorsa yapabilirsiniz, ancak çalışma sırasında rastgele sayının gerekli boyutu değişirse (dinamik bir diziyi karıştırmak gibi) böyle bir uyarı etrafında çalışmak zor olacaktır.
dreamlax

Burada herhangi bir rastgele fonksiyon bulamıyorum :-(
kasia.b

@ kasia.b bu linkte, extern int rand(void);ve var extern void srand(unsigned int);.
RastaJedi

7

ISAAC'a (Dolaylı, Shift, Biriktir, Ekle ve Say) göz atın . Eşit dağılmış ve ortalama döngü uzunluğu 2 ^ 8295'tir.


2
ISAAC, hızı nedeniyle ilginç bir RNG'dir, ancak henüz ciddi bir şifreleme dikkati almamıştır.
user2398029

4

Bu, seçtiğiniz iki sayı arasında rastgele bir sayı almanın iyi bir yoludur.

#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));
}

İlk çıkış: 39

İkinci kez çıktı: 61

Üçüncü kez çıktı: 65

Sonraki değerleri randnumseçtiğiniz sayılara göre değiştirebilirsiniz ve bu iki sayı arasında sizin için rastgele bir sayı oluşturur.


4

Kullanmak istiyorsun rand(). Not ( ÇOK ÖNEMLİ ): rand işlevi için tohumu ayarladığınızdan emin olun. Bunu yapmazsanız, rastgele sayılarınız gerçekten rastgele değildir . Bu çok, çok, çok önemli. Neyse ki, genellikle iyi bir tohum almak için sistem keneler zamanlayıcı ve tarihin bir kombinasyonunu kullanabilirsiniz.


6
İki nokta a) Rastgele sayılarınız, jeneratörü nasıl tohumlatsanız da "gerçekten" rastgele değildir. Ve b) sözde rastgele dizinin birçok durumda her zaman aynı olması çok uygundur - örneğin test için.

16
Numaranızın gerçekten rastgele olması ÇOK ÖNEMLİ ise, rand () işlevini kullanmamalısınız.
tylerl

1
Rand'ın değerleri, tohumun ayarlanmasına bakılmaksızın hiç "gerçekten" rastgele değildir. Bilinen bir tohum verildiğinde dizi tahmin edilebilir. "Gerçekten" rastgele sayı üretimi zordur. Rand ile ilgili entropi yoktur.
dreamlax

2
Tabii ki yapacaklar - jeneratör sizin için kütüphane tarafından tohumlandı (muhtemelen sıfıra, ancak bu geçerli bir tohum).

4
Ah, ancak bilinen algoritma / bilinen tohum, rasgele sayılar kullanan herhangi bir programda hata ayıklamak için gereklidir. Daha ayrıntılı bir analiz için yeniden oluşturulabilmesi için kullanılan tohumun bir simülasyon çalışmasıyla birlikte kaydedilmesi olağandışı değildir. Srand () öğesini çağırmamak, srand (1) öğesini çağırmakla eşdeğerdir.
RBerteig

4

FWIW, cevap şu ki, evet, stdlib.hdenilen bir fonksiyon var rand; bu işlev, öngörülemezlik için değil, öncelikli olarak hız ve dağıtım için ayarlanır. Çeşitli diller ve çerçeveler için neredeyse tüm yerleşik rastgele işlevler varsayılan olarak bu işlevi kullanır. Daha az tahmin edilebilir, ancak çok daha yavaş çalışan "kriptografik" rastgele sayı üreteçleri de vardır. Bunlar güvenlikle ilgili her türlü uygulamada kullanılmalıdır.


4

Umarım sadece kullanmaktan biraz daha rastgeledir 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());
}

1
srand (rand ()) eklenmesi, bu program 1 saniye içinde birden çok kez yürütülürse dizinin rasgeleliğini arttırmaz. zaman (NULL) hala her biri için aynı değeri döndürür, ilk rand () aynı uzun döndürür ve ikinci srand () çağrısı aynı değerde olur ve aynı rastgele sıraya sahip olur. Argc adresinin kullanımı, ancak bu adresin programın her yürütmesinde farklı olacağı garanti edilirse (ki bu her zaman doğru değildir) yardımcı olabilir.
theferrit32

3

STL C ++, C değil, bu yüzden ne istediğini bilmiyorum. Bununla birlikte, C'yi istiyorsanız, rand()ve srand()işlevleri vardır:

int rand(void);

void srand(unsigned seed);

Bunlar, aynı zamanda var olan ANSI C'ye her iki parçası random()işlevi:

long random(void);

Ancak anlayabildiğim kadarıyla random()standart ANSI C değil. Üçüncü taraf bir kütüphane kötü bir fikir olmayabilir, ancak hepsi gerçekten bir sayının ne kadar rastgele üretmeniz gerektiğine bağlıdır.


3

C 9 ile 50 arasında rastgele sayı üretecek program

#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);
}

Genel olarak lowerLimit ve upperLimit-1 arasında rastgele bir sayı üretebiliriz

Yani lowerLimit kapsayıcıdır veya r ∈ [lowerLimit, upperLimit) deyin


@Pang 9 ile 50 arasında değil 9 ile 50 arasında açıkça bahsettiğim şey bu.
Shivam K. Thakkar

2
Modulo işleminiz bir yanlılık yarattı.
JWW

2

rand() rastgele sayılar üretmenin en uygun yoludur.

Ayrıca random.org gibi herhangi bir çevrimiçi hizmetten rastgele sayı yakalayabilirsiniz.


1
Ayrıca C'de taşınabilir ve etkili bir yol eklerseniz random.org Bounty gibi herhangi bir çevrimiçi hizmetten rastgele sayı yakalayabilirsiniz
MD XF

2
#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]);
}

sonra üstte değişkenler ile tanımlayın @ b4hand
Muhammad Sadiq

Bu yorumu yaptığımda, evrensel düzenleme izinlerine sahip değildim ve genellikle gerçek cevabı değiştiren kod değişiklikleri reddedilecekti. Cevabınızı düzeltmek istemezseniz, yapabilirim.
b4hand

Amacınız benzersiz değerlerin rastgele bir permütasyonunu üretmekse, bu kodun hala bir hatası vardır. 84 değerini iki kez üretir ve 48 değerini üretmez. Ayrıca, rasgele sayı üretecini tohumlamaz, bu nedenle sıra her yürütmede aynıdır.
b4hand

1
a ve b değişkenleri bu kodda tanımlanmıştır. Hatasızdır .. sözdizimi ve mantıksal hata da yoktur.
Muhammed Sadık

Yanlış. Daha önce de belirttiğim gibi çıktıyı elle onayladım.
b4hand

1
#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;
}

1

Modern x86_64 işlemcilerinde donanım rasgele sayı üretecini _rdrand64_step()

Örnek 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

1
#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;
}

0

rand()Belirli bir aralıkta düzgün dağılmış rasgele sayılar üretmek için kullanmanın kötü bir fikir olduğunu iyi bir şekilde duyduğumda, çıktının gerçekte ne kadar çarpık olduğuna bir göz atmaya karar verdim. Test durumum adil zar atmaktı. İşte C kodu:

#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);
}

ve işte çıktısı:

 $ 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%

Rastgele sayılarınızın ne kadar üniform olması gerektiğini bilmiyorum, ancak yukarıdakiler çoğu ihtiyaç için yeterince üniform görünüyor.

Düzenleme: PRNG daha iyi bir şey ile başlatmak için iyi bir fikir olacaktır time(NULL).


rand () diehard testleri gibi diğer rastgele testlerde başarısız olabilir . rand () platformdan platforma farklılık gösterir; GNU / Linux'tan rand () değerleri BSD veya Windows değerlerinden daha iyi olabilir.
George Koehler

Bu, rastgeleliği test etmek için geçerli bir yol değildir.
Veedrac

Amaca ve tehdit / risk modeline bağlıdır. Kriptografik olarak güçlü RNG için - elbette, RDRAND (veya RDSEED) kullanın. Basit bir zar atıcısı (casino düzeyinde değil) IMHO için yukarıdaki yeterlidir. Anahtar kelime " yeterince iyi ".
Fare

0

Son uygulamada sözde rasgele sayı üreteci ile ciddi bir sorun vardı: tekrar tekrar bir pyhton komut dosyası aracılığıyla C programımı çağırdı ve tohum olarak aşağıdaki kodu kullanıyordum:

srand(time(NULL))

Ancak, şu tarihten beri:

  • rand, aynı sahte rasgele sekansı üretecek ve aynı tohumun tohum içinde verilmesini sağlayacaktır (bakınız man srand);
  • Daha önce de belirtildiği gibi, zaman işlevi sadece saniyeden saniye saniye değişir: uygulamanız aynı saniye içinde birden çok kez çalıştırılırsa, timeher seferinde aynı değeri döndürür.

Programım aynı sayı dizisini üretti. Bu sorunu çözmek için 3 şey yapabilirsiniz:

  1. çalışır durumda değişen diğer bazı bilgiler ile zaman çıktısını karıştır (benim uygulama, çıktı adı):

    srand(time(NULL) | getHashOfString(outputName))

    Hash fonksiyonum olarak djb2 kullandım .

  2. Zaman çözünürlüğünü artırın. Platformumda clock_gettimemevcuttu, bu yüzden kullanıyorum:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec);
  3. Her iki yöntemi birlikte kullanın:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec | getHashOfString(outputName));

Seçenek 3 (bildiğim kadarıyla) en iyi tohum rasgeleliğini sağlar, ancak sadece çok hızlı uygulamada bir fark yaratabilir. Bence seçenek 2 güvenli bir bahis.


Bu buluşsal yöntemlerle bile, kriptografik veriler için rand () yöntemine güvenmeyin.
domenukk

rand()kriptografik veriler için kullanılmamalıdır, katılıyorum. En azından benim için, uygulamam şifreleme verisi içermiyordu, bu yüzden benim için verilen yöntem iyiydi.
Koldar

0

rand()Burada tüm insanların önerilerine rağmen , rand()gerekmedikçe kullanmak istemezsiniz ! Üreten rastgele sayılar rand()genellikle çok kötüdür. Linux kılavuz sayfasından alıntı yapmak için:

Versiyonları rand()ve srand()Linux C Kütüphanesi ile aynı üretici kullanılmaktadır random(3)ve srandom(3)düşük bitler daha yüksek bitleri gibi rasgele gibi olmalıdır, böylece. Bununla birlikte, daha eski rand () uygulamalarında ve farklı sistemlerde mevcut uygulamalarda , düşük dereceli bitler yüksek dereceli bitlerden çok daha az rastgeledir . İyi rasgelelik gerektiğinde taşınabilir olması amaçlanan uygulamalarda bu işlevi kullanmayın. ( Bunun yerine kullanın random(3). )

Taşınabilirlik ile ilgili olarak random(), POSIX standardı tarafından bir süredir tanımlanmaktadır. rand()daha eski, ilk POSIX.1 spesifikasyonunda (IEEE Std 1003.1-1988) random()ortaya çıktı , ilk olarak POSIX.1-2001'de (IEEE Std 1003.1-2001) ortaya çıktı, ancak mevcut POSIX standardı zaten POSIX.1-2008 (IEEE Std 1003.1-2008), sadece bir yıl önce bir güncelleme aldı (IEEE Std 1003.1-2008, 2016 Sürümü). Bu yüzden random()çok taşınabilir olmayı düşünürdüm .

POSIX.1-2001 lrand48()ve mrand48()işlevlerini de tanıttı, buraya bakın :

Bu işlev ailesi, doğrusal bir eş algoritma ve 48 bit tam sayı aritmetiği kullanılarak sözde rasgele sayılar üretecektir.

Ve oldukça iyi sözde rastgele kaynak arc4random()birçok sistemde bulunan işlevdir. Herhangi bir resmi standardın parçası değil, 1997'de BSD'de ortaya çıktı, ancak Linux ve macOS / iOS gibi sistemlerde bulabilirsiniz.


random()Windows'ta mevcut değil.
Björn Lindqvist

@ BjörnLindqvist Windows da POSIX sistemi değildir; piyasadaki en azından temel POSIX API'lerini (iOS gibi desteklemeyen sistemleri bile kilitlemeyen) desteklemeyen tek sistemdir. Windows yalnızca rand()C standardı için gerekli olduğu için destekliyor . Her şey için, her zamanki gibi sadece Windows için özel bir çözüme ihtiyacınız var. #ifdef _WIN32en çok Windows'u desteklemek isteyen platformlar arası kodda göreceğiniz ve genellikle tüm sistemlerle çalışan ve yalnızca Windows için gerekli olan bir çözüm var.
Mecki

0

Linux C uygulamaları için:

Bu benim C kodu uygulamaları takip ve herhangi bir boyutta (uygun dönüş kodları, vb ile) rastgele bir tampon döndürür yukarıdaki bir cevap yeniden işlenmiş kodu. urandom_open()Programınızın başında bir kez aradığınızdan emin olun .

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;
    }
}

-2

Minimalist çözümüm aralıktaki rastgele sayılar için çalışmalıdır [min, max). srand(time(NULL))İşlevi çağırmadan önce kullanın .

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));
} 

-3

Bunu deneyin, yukarıda yukarıda belirtilen bazı kavramlardan bir araya getirdim:

/*    
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;
}

16
Bu kod iyi değil. Arayan srand()çağrıya istediğiniz her zaman rand()çok kötü bir fikir. Beri time()tipik bir değer döndürür saniye aynı "rasgele" değeri döndürecektir hızla bu işlevi çağırarak.
Blastfurnace

3
Bu işlev Unix'in random()işleviyle karıştırılır .
George Koehler
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.