Bagaimana cara menghasilkan int acak dalam C?

Jawaban:

663

Catatan : Jangan gunakan rand()untuk keamanan. Jika Anda memerlukan nomor yang aman secara kriptografis, lihat jawaban ini sebagai gantinya.

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

Sunting : Di Linux, Anda mungkin lebih suka menggunakan acak dan acak .

Łukasz Lew
sumber
194
Memberi +1 untuk kesederhanaan, tetapi mungkin ide yang baik untuk menekankan bahwa srand () hanya boleh dipanggil satu kali . Juga, dalam aplikasi berulir, Anda mungkin ingin memastikan bahwa keadaan generator disimpan per utas, dan menaburkan generator satu kali untuk setiap utas.
RBerteig
41
@trusktr, ini rumit. Inilah alasannya: time()hanya berubah sekali per detik. Jika Anda memotong dari time(), untuk setiap panggilan rand(), maka Anda akan mendapatkan nilai yang sama untuk setiap panggilan selama satu detik. Tetapi alasan yang lebih besar adalah bahwa properti rand()dan fungsi seperti itu dikenal terbaik untuk use case di mana mereka diunggulkan tepat sekali per run, dan tidak pada setiap panggilan tunggal. Bergantung pada "keacakan" dengan properti yang belum diuji atau tidak terbukti menyebabkan masalah.
RBerteig
9
@trusktr untuk generator kongruensial linier sederhana (yang rand()biasanya adalah) penyemaian dengan cara rand()terbaik tidak akan berpengaruh sama sekali, dan paling buruk akan merusak kualitas generator yang diketahui. Ini adalah subjek yang mendalam. Mulailah dengan membaca Knuth Vol 2 Bab 3 pada angka acak sebagai pengantar terbaik untuk matematika dan perangkap.
RBerteig
21
Hindari peringatan kompiler dengan gips:srand((unsigned int)time(NULL));
GiovaMaster
9
Perlu diingat bahwa ini masih merupakan cara yang lemah untuk melihat PRNG. Baru tahun lalu, virus tipe cryptolocker di Linux membuat kesalahan dengan menyemai waktu, dan ini secara dramatis mengurangi ruang pencarian. Yang harus Anda lakukan adalah mendapatkan ide yang layak kapan infeksi terjadi dan kemudian coba benih dari sekitar waktu itu. Terakhir saya dengar, sumber keacakan yang terbaik adalah / dev / urandom, yang konon diunggulkan dari mashup sumber chaotic-ish seperti suhu pada perangkat keras. Namun, jika yang benar-benar Anda inginkan adalah agar program Anda bertindak berbeda pada setiap proses, solusi di atas baik-baik saja.
Jemenake
238

The rand()fungsi dalam <stdlib.h>pengembalian integer pseudo-acak antara 0 dan RAND_MAX. Anda bisa menggunakan srand(unsigned int seed)untuk mengatur seed.

Ini adalah praktik umum untuk menggunakan %operator bersamaan rand()untuk mendapatkan rentang yang berbeda (meskipun perlu diingat bahwa ini agak menghilangkan keseragaman). Sebagai contoh:

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

Jika Anda benar-benar peduli tentang keseragaman, Anda dapat melakukan sesuatu seperti ini:

/* 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;
  }
}
Laurence Gonsalves
sumber
18
Ini adalah praktik umum yang baik-baik saja, tetapi bukan yang benar. Lihat ini dan ini .
Lazer
35
@ Lazer: Itu sebabnya saya berkata "meskipun perlu diingat bahwa ini agak menghilangkan keseragaman".
Laurence Gonsalves
3
@AbhimanyuAryan %Adalah operator modulus. Ini memberi Anda sisa dari divisi integer, jadi x % nakan selalu memberi Anda nomor di antara 0dan n - 1(selama xdan nkeduanya positif). Jika Anda masih merasa itu membingungkan, cobalah menulis sebuah program yang memiliki ihitungan dari 0 hingga 100, dan cetak i % nuntuk beberapa npilihan Anda yang lebih kecil dari 100.
Laurence Gonsalves
2
@necromancer Saya melanjutkan dan menambahkan solusi yang sangat seragam.
Laurence Gonsalves
2
@Lazer, tautan kedua yang Anda poskan sebenarnya masih belum seragam sempurna. Melakukan double dan back tidak membantu. Link pertama Anda diposting memiliki solusi sempurna seragam, meskipun itu akan loop banyak untuk batas atas kecil. Saya telah menambahkan solusi yang sangat seragam untuk jawaban ini yang seharusnya tidak berulang bahkan untuk batas atas kecil.
Laurence Gonsalves
53

Jika Anda memerlukan karakter atau integer acak yang aman:

Sebagaimana dibahas dalam cara menghasilkan angka acak dengan aman dalam berbagai bahasa pemrograman , Anda harus melakukan salah satu dari yang berikut:

Sebagai contoh:

#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() aman secara kriptografis dan tidak bias.

Scott Arciszewski
sumber
haruskah libsodium RNG diunggulkan sebelum memanggil randombytes_buf?
user2199593
Panggil saja sodium_init()di beberapa titik. Jangan khawatir tentang RNG, karena menggunakan kernel.
Scott Arciszewski
Catatan: Saya menyetujui hasil edit baru-baru ini sodium_init()walaupun itu belum tentu menjadi bagian dari contoh saya karena ini merupakan detail penting.
Scott Arciszewski
29

Mari kita pergi melalui ini. Pertama-tama kita menggunakan fungsi srand () untuk seed randomizer. Pada dasarnya, komputer dapat menghasilkan angka acak berdasarkan nomor yang diumpankan ke srand (). Jika Anda memberikan nilai seed yang sama, maka angka acak yang sama akan dihasilkan setiap waktu.

Oleh karena itu, kita harus menyemai randomizer dengan nilai yang selalu berubah. Kami melakukan ini dengan memberinya nilai waktu saat ini dengan fungsi time ().

Sekarang, ketika kita memanggil rand (), nomor acak baru akan dihasilkan setiap saat.

#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;
}
Abhay Budakoti
sumber
12
Kode yang bagus, tetapi bukan ide yang baik untuk memanggil 'srand (waktu (NULL));'. metode ini menghasilkan angka yang sama ketika dipanggil dalam for loop.
RayOldProf
1
Pengeditan yang disarankan yang melibatkan kode sering ditolak. Seseorang membuat satu di sini dengan komentar "algoritma salah. Bisa menghasilkan angka lebih besar dari maksimum". Saya belum mengevaluasi klaim itu sendiri.
Martin Smith
1
Masalah @Martin Smith: 1) harus else{ low_num=max_num; hi_num=min_num+1;2) gagal saat hi_num - low_num > INT_MAX. 3) Menghilangkan nilai dalam situasi yang jarang terjadi INT_MAX > hi_num - low_num > RAND_MAX.
chux - Reinstate Monica
1
Mengembalikannya seperti ini akan menyebabkan fungsi ini menghasilkan angka yang sama jika dipanggil beberapa kali dalam detik yang sama. Jika Anda benar-benar ingin me-reseed, maka hanya me-reseed sekali per detik.
Élektra
1
Minor: hi_num = max_num + 1;tidak memiliki perlindungan terhadap luapan.
chux - Reinstate Monica
25

Jika Anda membutuhkan nomor acak semu yang lebih baik daripada yang stdlibdisediakan, periksa Mersenne Twister . Lebih cepat juga. Implementasi sampel berlimpah, misalnya di sini .

MH114
sumber
2
+1: Terlihat keren tapi saya baru saja membuat permainan menebak. Jika saya akan menggunakan generator nomor acak dalam aplikasi bisnis maka saya pasti akan menggunakan ini.
Kredns
4
Jangan gunakan Mersenne Twister, gunakan sesuatu yang bagus seperti xoroshiro128 + atau PCG. (Tautan yang relevan.)
Veedrac
17

Fungsi standar C adalah rand(). Cukup bagus untuk menangani kartu untuk solitaire, tapi itu mengerikan. Banyak implementasi rand()siklus melalui daftar angka pendek, dan bit rendah memiliki siklus yang lebih pendek. Cara beberapa program menyebutnya rand()mengerikan, dan menghitung benih yang baik untuk dilewatkan srand()adalah sulit.

Cara terbaik untuk menghasilkan angka acak dalam C adalah dengan menggunakan perpustakaan pihak ketiga seperti OpenSSL. Sebagai contoh,

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

Mengapa begitu banyak kode? Bahasa lain seperti Java dan Ruby memiliki fungsi untuk bilangan bulat acak atau float. OpenSSL hanya memberikan byte acak, jadi saya mencoba untuk meniru bagaimana Java atau Ruby akan mengubahnya menjadi bilangan bulat atau mengapung.

Untuk bilangan bulat, kami ingin menghindari bias modulo . Misalkan kita mendapatkan beberapa bilangan bulat 4 digit acak rand() % 10000, tetapi rand()hanya dapat mengembalikan 0 hingga 32767 (seperti halnya di Microsoft Windows). Setiap angka dari 0 hingga 2767 akan muncul lebih sering daripada setiap angka dari 2768 hingga 9999. Untuk menghapus bias, kita dapat mencoba lagi rand()sementara nilainya di bawah 2768, karena nilai-nilai 30000 dari 2768 hingga 32767 memetakan secara seragam ke nilai 10000 dari 0 hingga 9999.

Untuk mengapung, kami ingin 53 bit acak, karena doublememegang 53 bit presisi (dengan asumsi itu adalah ganda IEEE). Jika kita menggunakan lebih dari 53 bit, kita mendapatkan bias pembulatan. Beberapa programmer menulis kode seperti rand() / (double)RAND_MAX, tetapi rand()mungkin mengembalikan hanya 31 bit, atau hanya 15 bit di Windows.

RAND_bytes()Benih OpenSSL sendiri, mungkin dengan membaca /dev/urandomdi Linux. Jika kita memerlukan banyak angka acak, akan terlalu lambat untuk membacanya /dev/urandom, karena mereka harus disalin dari kernel. Lebih cepat untuk memungkinkan OpenSSL menghasilkan lebih banyak angka acak dari sebuah seed.

Lebih lanjut tentang angka acak:

George Koehler
sumber
Terima kasih atas jawaban yang diperluas ini. Perhatikan bahwa dari 24 jawaban saat ini untuk pertanyaan ini, Anda adalah satu-satunya yang memiliki interpretasi ekstra untuk menangani float/ double, jadi saya telah mengklarifikasi pertanyaan untuk tetap berpegang pada intangka untuk menghindari membuatnya terlalu luas. Ada pertanyaan C lain yang berhubungan secara khusus dengan float/ doublenilai acak, jadi Anda mungkin ingin memposting ulang bagian kedua dari jawaban Anda untuk pertanyaan seperti stackoverflow.com/questions/13408990/…
Cœur
11

Jika sistem Anda mendukung arc4randomkeluarga fungsi, saya akan merekomendasikan menggunakan randfungsi standar saja .

The arc4randomkeluarga meliputi:

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 mengembalikan bilangan bulat unsigned 32-bit acak.

arc4random_bufmenempatkan konten acak di parameternya buf : void *. Jumlah konten ditentukan oleh bytes : size_tparameter.

arc4random_uniformmengembalikan bilangan bulat 32-bit unsigned acak yang mengikuti aturan:, di 0 <= arc4random_uniform(limit) < limitmana batasnya juga merupakan integer 32-bit yang tidak ditandatangani.

arc4random_stirmembaca data dari /dev/urandomdan meneruskan data arc4random_addrandomke juga mengacak kumpulan angka acak internal itu.

arc4random_addrandomdigunakan oleh arc4random_stiruntuk mengisi kumpulan nomor acak internal itu menurut data yang diteruskan ke sana.

Jika Anda tidak memiliki fungsi-fungsi ini, tetapi Anda berada di Unix, maka Anda dapat menggunakan kode ini:

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

The urandom_initFungsi membuka /dev/urandomperangkat, dan menempatkan file descriptor di urandom_fd.

The urandomFungsi dasarnya adalah sama sebagai panggilan untuk rand, kecuali lebih aman, dan mengembalikan long(mudah berubah).

Namun, /dev/urandombisa sedikit lambat, sehingga Anda disarankan menggunakannya sebagai seed untuk generator angka acak yang berbeda.

Jika sistem Anda tidak memiliki /dev/urandom, tapi tidak memiliki /dev/randomatau file yang sama, maka Anda hanya bisa mengubah jalan dilewatkan ke opendalam urandom_init. Panggilan dan API yang digunakan dalam urandom_initdan urandom(saya percaya) POSIX-compliant, dan dengan demikian, harus bekerja pada sebagian besar, jika tidak semua sistem yang sesuai dengan POSIX.

Catatan: Pembacaan dari /dev/urandomTIDAK akan memblokir jika ada cukup entropi yang tersedia, sehingga nilai yang dihasilkan dalam keadaan seperti itu mungkin tidak aman secara kriptografis. Jika Anda khawatir tentang itu, maka gunakan /dev/random, yang akan selalu memblokir jika ada cukup entropi.

Jika Anda berada di sistem lain (yaitu Windows), maka gunakan randatau API non-portabel yang bergantung pada platform khusus Windows internal.

Wrapper fungsi untuk urandom, randatau arc4randompanggilan:

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

int myRandom(int bottom, int top){
    return (RAND_IMPL() % (top - bottom)) + bottom;
}
Élektra
sumber
8

STL tidak ada untuk C. Anda harus menelepon rand, atau lebih baik lagi random,. Ini dideklarasikan di header perpustakaan standar stdlib.h. randadalah POSIX, randomadalah fungsi spesifikasi BSD.

Perbedaan antara randdan randomadalah yang randommengembalikan angka acak 32-bit yang lebih dapat digunakan, dan randbiasanya mengembalikan angka 16-bit. Halaman manual BSD menunjukkan bahwa bit yang lebih rendah randbersifat siklik dan dapat diprediksi, sehingga randberpotensi tidak berguna untuk jumlah kecil.

dreamlax
sumber
3
@ Neil - karena semua jawaban sejauh ini menyebutkan STL, saya curiga bahwa pertanyaan itu diedit cepat untuk menghapus referensi yang tidak perlu.
Michael Burr
rand () tidak berguna untuk jumlah kecil - Anda dapat menggeser bitnya keluar dan hanya menggunakan bit tinggi lebih acak jika Anda benar-benar perlu.
Chris Lutz
@ Chris, Anda bisa jika ukuran nomor acak diketahui, tetapi jika ukuran yang diperlukan dari nomor acak berubah selama runtime (seperti mengocok array dinamis dll) akan sulit untuk mengatasi peringatan semacam itu.
dreamlax
Saya tidak dapat menemukan fungsi acak apa pun di sini :-(
kasia.b
@ kasia.b di tautan itu, ada extern int rand(void);dan extern void srand(unsigned int);.
RastaJedi
7

Lihatlah ISAAC (Indirection, Shift, Accumulate, Add, and Count). Didistribusikan secara seragam dan memiliki panjang siklus rata-rata 2 ^ 8295.

geofftnz
sumber
2
ISAAC adalah RNG yang menarik karena kecepatannya tetapi belum menerima perhatian kriptografi yang serius.
user2398029
4

Ini adalah cara yang baik untuk mendapatkan angka acak antara dua angka pilihan Anda.

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

Keluaran pertama kali: 39

Keluaran untuk kedua kalinya: 61

Keluaran yang ketiga kalinya: 65

Anda dapat mengubah nilai setelah randnumke nomor apa pun yang Anda pilih, dan itu akan menghasilkan angka acak untuk Anda di antara dua angka itu.

pembuat kode
sumber
4

Anda ingin menggunakan rand(). Catatan ( SANGAT PENTING ): pastikan untuk mengatur seed untuk fungsi rand. Jika tidak, angka acak Anda tidak benar-benar acak . Ini sangat, sangat, sangat penting. Untungnya, Anda biasanya dapat menggunakan beberapa kombinasi pengingat waktu sistem dan tanggal untuk mendapatkan seed yang bagus.

Paul Sonier
sumber
6
Dua poin a) angka acak Anda tidak acak, tidak peduli bagaimana Anda menyemai generator. Dan b) sangat mudah untuk memiliki urutan pseudo-acak selalu sama dalam banyak keadaan - untuk pengujian, misalnya.
16
jika SANGAT PENTING bahwa nomor Anda benar-benar acak, Anda tidak boleh menggunakan fungsi rand ().
tylerl
1
Nilai-nilai dari rand sama sekali tidak "benar-benar" acak tidak peduli apakah Anda mengatur seed atau tidak. Diberikan benih yang dikenal urutannya dapat diprediksi. Pembuatan nomor acak "Sungguh" itu sulit. Tidak ada entropi yang terlibat dengan rand.
dreamlax
2
Tentu saja mereka akan - generator diunggulkan untuk Anda oleh perpustakaan (mungkin ke nol, tapi itu benih yang valid).
4
Ah, tetapi algoritma yang dikenal / dikenal benih sangat penting untuk debugging setiap program yang menggunakan angka acak. Bukan tidak biasa untuk mencatat benih yang digunakan bersamaan dengan simulasi sehingga dapat diciptakan kembali untuk analisis yang lebih rinci. Sama sekali tidak memanggil srand () sama dengan memanggil srand (1).
RBerteig
4

FWIW, jawabannya adalah ya, ada stdlib.hfungsi yang disebut rand; fungsi ini disetel terutama untuk kecepatan dan distribusi, bukan untuk ketidakpastian. Hampir semua fungsi acak bawaan untuk berbagai bahasa dan kerangka kerja menggunakan fungsi ini secara default. Ada juga generator nomor acak "kriptografi" yang jauh lebih mudah diprediksi, tetapi berjalan jauh lebih lambat. Ini harus digunakan dalam segala jenis aplikasi yang berhubungan dengan keamanan.

tylerl
sumber
4

Mudah-mudahan ini sedikit lebih acak daripada hanya menggunakan 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());
}
kenorb
sumber
1
menambahkan srand (rand ()) tidak meningkatkan keacakan urutan jika program ini dijalankan beberapa kali dalam 1 detik. waktu (NULL) masih akan mengembalikan nilai yang sama untuk masing-masing, rand pertama () akan mengembalikan panjang yang sama, dan panggilan kedua ke srand () akan dengan nilai yang sama, sehingga masih memiliki urutan acak yang sama. Penggunaan alamat argc dapat membantu, hanya jika dijamin bahwa alamat ini akan berbeda pada setiap pelaksanaan program, yang tidak selalu benar.
theferrit32
3

STL adalah C ++, bukan C, jadi saya tidak tahu apa yang Anda inginkan. Namun, jika Anda menginginkan C, ada rand()dan srand()fungsinya:

int rand(void);

void srand(unsigned seed);

Keduanya adalah bagian dari ANSI C. Ada juga random()fungsinya:

long random(void);

Tapi sejauh yang saya tahu, random()itu bukan standar ANSI C. Perpustakaan pihak ketiga mungkin bukan ide yang buruk, tetapi semuanya tergantung pada seberapa acak angka yang benar-benar Anda butuhkan untuk menghasilkan.

Chris Lutz
sumber
3

Program C untuk menghasilkan angka acak antara 9 dan 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);
}

Secara umum kita dapat menghasilkan angka acak antara lowerLimit dan upperLimit-1

yaitu lowerLimit termasuk atau katakan r ∈ [lowerLimit, upperLimit)

Shivam K. Thakkar
sumber
@ Pang Itulah yang saya jelaskan ANTARA 9 dan 50 bukan DARI 9 dan 50.
Shivam K. Thakkar
2
Operasi modulo Anda menimbulkan bias.
jww
2

rand() adalah cara paling mudah untuk menghasilkan angka acak.

Anda juga dapat memperoleh nomor acak dari layanan online seperti random.org.

Namit Sinha
sumber
1
Anda juga dapat memperoleh nomor acak dari layanan online seperti Bounty random.org jika Anda menyertakan cara portabel dan efisien untuk melakukan ini dalam C.
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]);
}
Muhammad Sadiq
sumber
lalu definisikan di atas dengan variabel @ b4hand
Muhammad Sadiq
Pada saat saya membuat komentar itu, saya tidak memiliki izin edit universal, dan umumnya perubahan kode yang mengubah jawaban yang sebenarnya akan ditolak. Jika Anda tidak peduli untuk memperbaiki jawaban Anda, saya bisa.
b4hand
Jika niat Anda adalah untuk menghasilkan permutasi acak dari nilai-nilai unik, kode ini masih memiliki bug. Ini menghasilkan nilai 84 dua kali dan tidak menghasilkan nilai 48. Selain itu, tidak menghasilkan generator nomor acak sehingga urutannya sama pada setiap eksekusi.
tangani
1
variabel a dan b didefinisikan dalam kode ini .. Ini bebas kesalahan .. tidak ada sintaks dan kesalahan logis juga.
Muhammad Sadiq
Salah. Saya sudah mengkonfirmasi output seperti yang saya sebutkan.
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;
}
Bisu vs Utsab
sumber
1

Pada CPU x86_64 modern Anda dapat menggunakan generator nomor acak perangkat keras via _rdrand64_step()

Kode contoh:

#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
Serge Rogatch
sumber
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;
}
shellhub
sumber
0

Mendengar penjelasan yang baik tentang mengapa menggunakan rand()untuk menghasilkan angka acak yang terdistribusi secara seragam dalam rentang yang diberikan adalah ide yang buruk, saya memutuskan untuk melihat bagaimana kemiringan output sebenarnya. Kasus tes saya adalah melempar dadu dengan adil. Ini kode 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);
}

dan inilah hasilnya:

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

Saya tidak tahu seberapa seragam Anda perlu nomor acak Anda, tetapi di atas tampak cukup seragam untuk sebagian besar kebutuhan.

Sunting: itu akan menjadi ide yang baik untuk menginisialisasi PRNG dengan sesuatu yang lebih baik daripada time(NULL).

Mouse
sumber
rand () dapat gagal dalam tes keacakan lainnya, seperti tes diehard . rand () berbeda dari platform ke platform; nilai rand () dari GNU / Linux mungkin lebih baik daripada nilai dari BSD atau Windows.
George Koehler
Ini bukan cara yang valid untuk menguji keacakan.
Veedrac
Tergantung pada tujuan dan model ancaman / risiko. Untuk RNG yang kuat secara kriptografis - tentu saja, gunakan RDRAND (atau RDSEED). Untuk pelempar dadu sederhana (bukan tingkat kasino) IMHO di atas sudah cukup. Kata kuncinya adalah " cukup baik ".
Mouse
0

Saya memiliki masalah serius dengan pseudo random generator angka dalam aplikasi saya baru-baru ini: Saya berulang kali memanggil program C saya melalui skrip pyhton dan saya gunakan sebagai seed kode berikut:

srand(time(NULL))

Namun, sejak:

  • rand akan menghasilkan urutan acak semu yang sama memberikan benih yang sama dalam srand (lihat man srand );
  • Seperti yang telah dinyatakan, fungsi waktu berubah hanya detik dari detik: jika aplikasi Anda dijalankan beberapa kali dalam detik yang sama, timeakan mengembalikan nilai yang sama setiap kali.

Program saya menghasilkan urutan angka yang sama. Anda dapat melakukan 3 hal untuk menyelesaikan masalah ini:

  1. mencampur output waktu dengan beberapa informasi lain yang berubah saat berjalan (dalam aplikasi saya, nama output):

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

    Saya menggunakan djb2 sebagai fungsi hash saya.

  2. Tambah resolusi waktu. Di platform saya, clock_gettimetersedia, jadi saya menggunakannya:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec);
  3. Gunakan kedua metode bersama-sama:

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

Opsi 3 memastikan Anda (sejauh yang saya tahu) keacakan benih terbaik, tetapi mungkin membuat perbedaan hanya pada aplikasi yang sangat cepat. Menurut saya opsi 2 adalah taruhan yang aman.

Koldar
sumber
Bahkan dengan heuristik ini, jangan bergantung pada rand () untuk data kriptografi.
domenukk
rand()tidak boleh digunakan untuk data kriptografi, saya setuju. Setidaknya bagi saya, aplikasi saya tidak melibatkan data kriptografi, jadi bagi saya itu ok metode yang diberikan.
Koldar
0

Terlepas dari semua saran orang di rand()sini, Anda tidak ingin menggunakan rand()kecuali Anda harus! Angka acak yang rand()menghasilkan seringkali sangat buruk. Mengutip dari halaman manual Linux:

Versi rand()dan srand()di Linux C Library menggunakan generator angka acak yang sama dengan random(3)dan srandom(3), sehingga bit urutan rendah harus acak seperti bit urutan yang lebih tinggi. Namun, pada implementasi rand () lama, dan pada implementasi saat ini pada sistem yang berbeda, bit orde rendah jauh lebih sedikit acak daripada bit orde tinggi . Jangan gunakan fungsi ini dalam aplikasi yang dimaksudkan untuk portabel ketika keacakan yang baik diperlukan. ( Gunakan random(3)saja. )

Mengenai portabilitas, random()juga ditentukan oleh standar POSIX untuk beberapa waktu sekarang. rand()lebih tua, sudah muncul di spec POSIX.1 pertama (IEEE Std 1003.1-1988), sedangkan yang random()pertama muncul di POSIX.1-2001 (IEEE Std 1003.1-2001), namun standar POSIX saat ini sudah POSIX.1-2008 (IEEE Std 1003.1-2008), yang menerima pembaruan setahun yang lalu (IEEE Std 1003.1-2008, Edisi 2016). Jadi saya akan mempertimbangkanrandom() sangat portabel.

POSIX.1-2001 juga memperkenalkan lrand48()dan mrand48()fungsinya, lihat di sini :

Rangkaian fungsi ini akan menghasilkan angka pseudo-acak menggunakan algoritma linear kongruensial dan aritmatika integer 48-bit.

Dan sumber acak semu yang cukup bagus adalah arc4random() fungsi yang tersedia di banyak sistem. Bukan bagian dari standar resmi apa pun, muncul di BSD sekitar tahun 1997 tetapi Anda dapat menemukannya di sistem seperti Linux dan macOS / iOS.

Mecki
sumber
random()tidak ada di Windows.
Björn Lindqvist
@ BjörnLindqvist Windows juga bukan sistem POSIX; itu cukup banyak satu-satunya sistem di pasar yang tidak mendukung setidaknya API POSIX dasar (yang bahkan mengunci sistem seperti iOS tidak mendukung). Windows hanya mendukung rand()karena juga diperlukan oleh standar C. Untuk hal lain, Anda memerlukan solusi khusus untuk Windows saja, seperti biasa. #ifdef _WIN32adalah ungkapan yang paling sering Anda lihat dalam kode lintas platform yang ingin mendukung Windows dan biasanya ada satu solusi yang bekerja dengan semua sistem dan satu yang diperlukan untuk Windows saja.
Mecki
0

Untuk aplikasi Linux C:

Ini adalah kode ulang saya dari jawaban di atas yang mengikuti praktik kode C saya dan mengembalikan buffer acak dalam berbagai ukuran (dengan kode pengembalian yang tepat, dll.). Pastikan untuk menelepon urandom_open()sekali di awal program Anda.

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;
    }
}
Brad Grissom
sumber
-2

Solusi minimalis saya harus bekerja untuk angka acak dalam jangkauan [min, max). Gunakan srand(time(NULL))sebelum memanggil fungsi.

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));
} 
Michał Ziobro
sumber
-3

Coba ini, saya menggabungkannya dari beberapa konsep yang telah dirujuk di atas:

/*    
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;
}
Pengguna
sumber
16
Kode ini tidak bagus. Menelepon srand()setiap kali Anda ingin menelepon rand()adalah ide yang buruk. Karena time()biasanya mengembalikan nilai dalam hitungan detik yang memanggil fungsi ini dengan cepat akan mengembalikan nilai "acak" yang sama.
Blastfurnace
3
Fungsi ini akan menjadi bingung dengan random()fungsi Unix .
George Koehler