Hasilkan bilangan bulat acak apa saja

17

Program / fungsi Anda harus

  • Output tepat satu integer
  • Output setiap bilangan bulat dengan probabilitas positif
  • menghasilkan bilangan bulat lebih besar dari 1.000.000 atau kurang dari -1.000.000 dengan setidaknya dengan probabilitas 50%.

Contoh output (semua harus dimungkinkan):

59875669123
12
-42
-4640055890
0
2014
12
24
-7190464664658648640055894646646586486400558904644646646586486400558904646649001

Klarifikasi:

  • Istirahat garis trailing diizinkan.
  • Angka nol di depan tidak diizinkan.
  • -0 diizinkan.

Kode terpendek menang.

randomra
sumber
2
@ Opptizer mengapa Anda mengasumsikan probabilitas yang sama? Pertanyaannya tidak menyatakannya. Bahkan nampak jelas dari titik itu bahwa distribusinya tidak harus seragam selama setidaknya 50% dari itu berada di luar [-1 juta, 1 juta].
hobbs
10
Solusi yang menghasilkan " distribusi seragam di semua bilangan bulat" tidak mungkin. Ada bilangan bulat tak terhingga banyaknya, sehingga setiap bilangan bulat individual akan muncul dengan probabilitas 0. (Atau: Mengeluarkan angka terbatas akan berarti Anda mengabaikan banyak bilangan tak terhingga!) Setiap solusi harus menolak nilai yang lebih tinggi untuk mencapai P (total ) = 1.
joeytwiddle
2
@Ypnypn RAM komputer juga tidak terbatas. Anda tidak perlu menyimpan output parsial Anda di mana pun.
jimmy23013
4
@GiantTree - way too long to fit in an integer- Ini hanya benar jika Anda menganggap itu integerberarti inttipe data pada lengkungan 32/64 bit, yang belum tentu asumsi yang valid. "Integer" dimulai sebagai istilah matematika , yang tidak memiliki batasan ukuran.
Nama Palsu
5
Siapa pun yang menggunakan generator angka acak semu untuk membuat keputusan pada output akan mengecualikan hampir semua bilangan bulat, dan menempatkan batas atas pada ukuran bilangan bulat yang dapat diproduksi (dengan asumsi bahwa PRNG memiliki periode yang terbatas). Apakah ini dapat diabaikan dalam jawaban atau apakah jawaban yang valid memerlukan generator nomor acak yang benar?
trichoplax

Jawaban:

12

CJam, 16 14 13 byte

0{Kmr(+esmr}g

Ini akan berjalan untuk waktu yang sangat lama, karena ia menggunakan cap waktu saat ini (pada urutan 10 12 ) untuk menentukan apakah loop harus diakhiri. Saya menggunakan ini sebagai kiriman, karena ini adalah yang terpendek, tetapi ada dua alternatif 14-byte, yang memiliki kelebihan sendiri:

0{esmr(+esmr}g

Yang ini tidak dibatasi oleh periode PRNG, karena rentang semua angka acak tergantung pada cap waktu saat ini. Oleh karena itu, ini harus dapat menghasilkan angka apa pun, walaupun kemungkinan untuk negatif, atau bahkan angka positif kecil semakin kecil.

Di bawah ini adalah versi yang setara yang menggunakan 3e5bukan timestamp. Dan 20untuk rentang pertama (seperti pengiriman 13 byte). Ini jauh lebih cepat dan juga mematuhi semua aturan. Ini adalah semacam pembatas kasus untuk mendapatkan probabilitas 50% untuk angka di atas 1.000.000 sambil menjaga runtime yang masuk akal dan ukuran kode kecil. Penjelasan dan pembenaran matematis merujuk pada versi ini:

0{Kmr(+3e5mr}g

Ini biasanya membutuhkan beberapa detik untuk berjalan. Anda dapat mengganti dengan 5dengan 2untuk membuatnya berjalan lebih cepat. Tetapi kemudian persyaratan 50% probabilitas hanya akan dipenuhi untuk 1.000, bukan 1.000.000.

Saya mulai dari 0. Kemudian saya mendapatkan satu lingkaran, yang saya hentikan dengan probabilitas 1 / (3 * 10 5 ). Dalam loop itu saya menambahkan bilangan bulat acak antara -1 dan 18 (inklusif) ke total berjalan saya. Ada probabilitas yang terbatas (walaupun kecil) bahwa setiap bilangan bulat akan menjadi output, dengan bilangan bulat positif lebih mungkin daripada yang negatif (saya tidak berpikir Anda akan melihat yang negatif dalam hidup Anda). Keluar dengan probabilitas sekecil itu, dan menambah sebagian besar waktu (dan menambahkan lebih banyak daripada mengurangi) memastikan bahwa kita biasanya melampaui 1.000.000.

0              "Push a 0.";
 {          }g "Do while...";
  Kmr          "Get a random integer in 0..19.";
     (         "Decrement to give -1..18.";
      +        "Add.";
       3e5mr   "Get a random integer in 0..299,999. Aborts if this is 0.";

Beberapa pembenaran matematika:

  • Di setiap langkah, kami menambahkan rata-rata 8,5.
  • Untuk mencapai 1.000.000 kita perlu 117.647 langkah-langkah ini.
  • Probabilitas yang akan kita lakukan kurang dari jumlah langkah ini adalah

    sum(n=0..117,646) (299,999/300,000)^n * 1/300,000
    

    yang dievaluasi menjadi 0.324402. Oleh karena itu, dalam sekitar dua pertiga dari kasus, kami akan mengambil 117.647 langkah, dan masing-masing 1.000.000.

  • (Perhatikan bahwa ini bukan probabilitas yang tepat, karena akan ada beberapa fluktuasi tentang rata-rata 8,5 itu, tetapi untuk mencapai 50%, kita harus melampaui 117.646 menjadi sekitar 210.000 langkah.)
  • Jika ragu, kita dapat dengan mudah meledakkan penyebut dari probabilitas terminasi, hingga 9e9tanpa menambahkan byte (tetapi bertahun-tahun runtime).

... atau 11 byte?

Akhirnya, ada versi 11 byte, yang juga tidak dibatasi oleh periode PRNG, tetapi yang akan kehabisan memori hampir setiap waktu. Ini hanya menghasilkan satu nomor acak (berdasarkan stempel waktu) setiap iterasi, dan menggunakannya baik untuk menambah dan mengakhiri. Hasil dari setiap iterasi tetap di stack dan hanya disimpulkan di akhir. Terima kasih kepada Dennis untuk ide ini:

{esmr(}h]:+
Martin Ender
sumber
Saya telah menambahkan komentar pada pertanyaan untuk melihat apakah aturannya membutuhkan penghasil angka acak yang benar, tetapi saya kira Anda akan menghargai keriaan itu. Apakah sumber acak Anda di sini pseudo random? Itu akan membatasi ukuran set output yang mungkin paling banyak periode PRNG Anda, kan?
trichoplax
(+1 terlepas dari keanggunan sederhana)
trichoplax
Ya, saya menebak sejauh ini. Saya ingin tahu apakah seseorang mengirim jawaban tanpa masalah itu ...
trichoplax
Saya melihat OP telah menyatakan bahwa Anda dapat menganggap generator nomor acak Anda adalah generator nomor acak yang sebenarnya apakah itu benar atau tidak - jadi ini berlebihan sekarang ... :)
trichoplax
Jumlah Kmrdalam suatu periode kemungkinan masih selalu merupakan angka positif besar yang lebih besar dari periode tersebut. Dan itu tidak dapat menghasilkan setiap angka yang mungkin dalam kasus itu.
jimmy23013
11

Jawa, 133 149

void f(){String s=x(2)<1?"-":"";for(s+=x(9)+1;x(50)>0;s+=x(10));System.out.print(x(9)<1?0:s);}int x(int i){return new java.util.Random().nextInt(i);}

Keluaran contoh

-8288612864831065123773
0
660850844164689214
-92190983694570102879284616600593698307556468079819964903404819
3264

Tidak disatukan

void f() {
    String s = x(2)<1 ? "-" : "";       // start with optional negative sign
    s+=x(9)+1;                          // add a random non-zero digit
    for(; x(50)>0; )                    // with a 98% probability...
        s+=x(10)                        // append a random digit
    System.out.print(x(9)<1 ? 0 : s);   // 10% chance of printing 0 instead
}

int x(int i) {
    return new java.util.Random().nextInt(i);
}

Jawaban lama (sebelum perubahan aturan)

void f(){if(Math.random()<.5)System.out.print('-');do System.out.print(new java.util.Random().nextInt(10));while(Math.random()>.02);}
Ypnypn
sumber
Anda
berdua
@Optimizer Redone.
Ypnypn
Jika Anda menggunakan literal biner, Anda tidak perlu mencetak -.
TheNumberOne
4

Mathematica - 47

Round@RandomVariate@NormalDistribution[0,15*^5]

Pada dasarnya hanya menghasilkan angka acak menggunakan distribusi normal dengan varians sama dengan 1500000. Ini akan menghasilkan bilangan bulat antara -10 ^ 6 dan 10 ^ 6 dengan probabilitas 49,5015%.

desir
sumber
"Ini akan menghasilkan bilangan bulat antara -10 ^ 6 dan 10 ^ 6 dengan probabilitas 50,4985%." - itu belum cukup. Apakah Anda salah membaca spek? Mungkin Anda bermaksud menggunakan 10 ^ 7 sebagai varians?
John Dvorak
@ JanDvorak Kemungkinan salah, maaf. Sekarang yang benar.
desir
Apakah implementasi ini dalam Mathematica benar-benar mencakup semua bilangan bulat? Saya tidak memiliki akses ke sumbernya tetapi saya kira tidak ...
trichoplax
@githubphagocyte Itu akan tergantung pada presisi saat ini.
desir
4
Yang saya maksud adalah, menentukan setiap presisi tertentu akan mengecualikan nomor lebih besar dari itu. Satu-satunya cara itu bisa berhasil adalah jika Anda dapat menentukan presisi tak terbatas.
trichoplax
4

Python 2, 75 69 byte

from random import*;s=0;j=randrange
while j(12):s=s*9+j(-8,9)
print s

Itu sepele untuk memeriksa bahwa loop sementara di tengah dapat menghasilkan semua bilangan bulat (meskipun bias terhadap nol). "12" dipilih sedemikian rupa sehingga kira-kira setengah dari angka yang melebihi ± 10 6 .


Solusi yang lebih lama:

Python 2, 44 byte

Berdasarkan solusi Mathematica .

from random import*;print int(gauss(0,8**7))

Tidak benar-benar berfungsi karena Python floathanya memiliki ketepatan terbatas.

kennytm
sumber
Ini tidak akan dapat menghasilkan semua bilangan bulat, karena generator angka pseudo-acak memiliki jumlah status internal yang terbatas. Menurut dokumentasi, Python menggunakan Mersenne Twister, jadi negara bagian ini cukup besar. Tetapi ini tidak terbatas, sehingga hanya dapat menghasilkan subset terbatas dari semua bilangan bulat.
starblue
@ starblue: Dari OP: "Anda dapat mengasumsikan bahwa penghasil angka acak bahasa Anda adalah penghasil bilangan acak yang sebenarnya meskipun bukan itu masalahnya."
kennytm
3

Ruby, 70

f=->{m=10**6
r=rand -m..m
r<1?(r>-5e5??-:'')+r.to_s+f[][/\d+/]:r.to_s}

Untuk membuat menghasilkan angka yang sangat besar, saya mengembalikan angka sebagai a String dari lambda. Jika itu tidak diizinkan, hitung 8 karakter tambahan (untuk puts f[]) untuk menjadikannya program alih-alih fungsi.

Penjelasan

Hasilkan nomor antara -1,000,000dan 1,000,000. Jika angkanya 1atau lebih tinggi, angkanya dikembalikan sebagai a String.

Jika angkanya lebih rendah dari 1, fungsinya disebut secara rekursif untuk mengembalikan nomor di luar rentang angka. Untuk memastikan angka negatif juga dapat dihasilkan, a -diawali dengan hasil Stringjika angka awal lebih besar dari -500,000.

Saya harap saya memahami tantangan dengan benar!

britishtea
sumber
3

R, 38

library(Rmpfr)
round(rnorm(1,2e6,1e6))

Penarikan dari distribusi Gaussian dengan rata-rata 2.000.000, dipilih secara acak, dan standar deviasi 1.000.000, sehingga sekitar 2/3 dari pengundian akan berada dalam 1.000.000 dan 3.000.000. Distribusi tidak terikat sehingga secara teori ini dapat menghasilkan bilangan bulat apa pun. Paket Rmpfr menggantikan R's built in double floats dengan presisi sewenang-wenang.

shadowtalker
sumber
Ya saya sadar saya salah membaca spec. Dan saya membayangkan itu memiliki keterbatasan yang sama pada presisi mesin dengan Mathematica
shadowtalker
Hmm dalam hal ini saya tidak yakin. Saya harus memeriksanya; pertimbangkan jawaban ini "ditahan" untuk saat ini
shadowtalker
@ MartinBüttner memperbaiki saya pikir
shadowtalker
Menarik. Saya pikir Anda tidak perlu sample(c(1,-1),1)berpikir secara keseluruhan . Hanya berpusat pada 1e6 sudah cukup ..
Martin Ender
@ MartinBüttner oh tidak perlu 50% di kedua ujungnya? Itu tidak jelas
shadowtalker
2

Perl, 53 karakter

print"-"if rand>.5;do{print int rand 10}while rand>.1

Saya jelas tidak melihat alasan untuk bekerja dengan bilangan bulat saat mencetaknya :)

Memiliki probabilitas yang sama untuk mencetak nomor dengan atau tanpa "-" pengarah.

Mencetak angka 1 digit 10% dari waktu, angka 2 digit 9% dari waktu, angka 3 digit 8,1% dari waktu, angka 4 digit 7,29% dari waktu, angka 5 digit 6,56% dari waktu, angka 6-digit 5,9% dari waktu, dll. Panjang mana pun dimungkinkan, dengan kemungkinan menurun. Angka satu hingga lima digit mencapai sekitar 41,5% dari kasus keluaran, dan jumlah 1.000.000 (atau -1.000.000) hanya 6 juta per persen, sehingga jumlah output akan berada di luar kisaran -1.000.000 hingga 1.000.000 sekitar 54,6 % waktu.

Baik "0" dan "-0" adalah output yang mungkin, yang saya harap tidak menjadi masalah.

hobbs
sumber
Bukankah ini mencetak "angka" seperti -00000000167? Itu bukan bilangan bulat.
isaacg
1
@isaacg Saya tidak melihat mengapa itu bukan bilangan bulat.
Pengoptimal
2
@Optimizer Ya, tapi OP secara eksplisit melarang memimpin 0.
Martin Ender
Anda bisa menghasilkan digit terdepan yang tidak nol sebelum loop, dari -9 hingga +9. print int(rand(20)-10)||1. Saya butuh cara untuk menghasilkan 0 sebagai output, meskipun. Mungkin || mati 0, jika sampah setelah nol dibolehkan. Lain perlu cara singkat untuk mencetak nol dan keluar tanpa output lebih lanjut jika int(rand(20)-10)==0.
Peter Cordes
@PeterCordes setuju, itu pendekatan yang layak tetapi saya tidak merasa ingin menulisnya dan saya pikir itu tidak akan kompetitif panjang. Jangan ragu untuk mengirimkannya sendiri :)
hobbs
2

Perl, 114 Chars

use Math::BigInt;sub r{$x=Math::BigInt->new(0);while(rand(99)!=0){$x->badd(rand(2**99)-2**98);}print($x->bstr());}

Kerusakan:

use Math::BigInt;               -- include BigIntegers
  sub r{                        -- Define subroutine "r"
    $x=Math::BigInt->new(0);    -- Create BigInteger $x with initial value "0"
      while(rand(99)!=0){       -- Loop around until rand(99) equals "0" (may be a long time)
        $x->badd(               -- Add a value to that BigInt
          rand(2**99)-2**98);   -- Generate a random number between -2^98 and +2^98-1
        }print($x->bstr());}    -- print the value of the BigInt

Peluang untuk mendapatkan nilai antara -1.000.000 dan 1.000.000 cenderung nol tetapi itu mungkin.

Catatan: Subrutin ini dapat berjalan untuk waktu yang lama dan kesalahan dengan "Kehabisan Memori!" kesalahan tapi itu teknis menghasilkan setiap bilangan bulat seperti yang dinyatakan dalam pertanyaan.

Perl, 25

sub r{rand(2**99)-2**98;}

Menghasilkan bilangan bulat acak dalam kisaran +/- 2 ^ 99.

Kerusakan

sub r{                    -- Define subroutine "r"
     rand(2**99)          -- Generate a random integer between 0 and 2^99
                -2**98;}  -- Subtract 2^98 to get negative values as well

Diuji dengan 1 juta sampel:

~5 are inside the range of +/-1.000.000
~999.995 are outside that range
= a probability of ~99,99% of generating an integer outside that range.
Compare that number to the probability of 2.000.000 in 2^99: It is approx. the same.

Ini memenuhi semua aturan:

  • 1 bilangan bulat
  • bilangan bulat apa pun dimungkinkan
  • setidaknya 50% (dalam kasus saya 99,99%) dari semua bilangan bulat yang dihasilkan berada di luar kisaran +/- 1.000.000.

Ini bekerja karena generator bilangan acak yang mendasari mendefinisikan probabilitas yang sama untuk setiap bit yang dihasilkan, sehingga melakukan hal itu pada bilangan bulat yang dihasilkan juga.
Setiap bilangan bulat memiliki probabilitas 1/2 ^ 99 yang akan dihasilkan.

Edit:

Saya harus meningkatkan eksponen sehingga bilangan bulat yang lebih besar dihasilkan. Saya memilih 99 karena menjaga kode sesingkat mungkin.

GiantTree
sumber
Bukankah kita sepakat bahwa tidak boleh ada batas atas / bawah? Misalnya, integer 2 ^ 31 + 1 memiliki 0 probabilitas, melanggar aturan 2
Pengoptimal
@ Opptizer bagi saya integer didefinisikan sebagai dalam banyak bahasa pemrograman: angka dalam batas -2^31dan +2^31-1(32 bit). Anda dapat dengan mudah meningkatkan eksponen jika Anda ingin menghasilkan bilangan bulat yang lebih besar tetapi mungkin gagal tergantung pada implementasi Perl.
GiantTree
Saya hanya melihat bahwa bilangan bulat yang sangat besar harus dihasilkan juga. Saya akan mengedit kode saya dengan cepat.
GiantTree
@ MartinBüttner Saya mencoba yang terbaik untuk memenuhi spesifikasi pertanyaan. Tidak mungkin bagi saya (setidaknya bukan tanpa bantuan) untuk menghasilkan bilangan bulat besar tanpa batas. Integer terbesar Perl adalah sekitar 1,7e308 yang merupakan batas yang tidak dapat saya kendalikan.
GiantTree
@ MartinBüttner Keduanya mungkin tetapi misalnya. string akan meluap setelah 2gb data menjadikannya terbatas. Sulit untuk mengatakan bahwa angka harus jauh lebih besar jika ada masalah dengan memori. Saya akan datang dengan pendekatan yang berbeda segera menggunakan BigInts. Juga bilangan bulat tidak meluap pada 1,7e308 itu hanya akan dikonversi menjadi infite ( 1.#INFtepatnya)
GiantTree
2

C #, 126 107 byte

string F(){var a=new System.Random();var b=a.Next(-1E6,1E6+1)+"";while(a.Next(1)>0)b+=a.Next(10);return b;}

Tidak Disatukan:

string F()
{
    System.Random rand = new System.Random();
    string rtn = rand.Next(-1E6, 1E6 + 1) + "";
    while (rand.Next(1) > 0)
         rtn += a.Next(10);
    return rtn;
}

Peluang untuk menghasilkan sejumlah n digit adalah 1/2 ^ (n-10), yang lebih besar dari 0 untuk semua n positif, dan 1/2 untuk n = 11.Juga menciptakan angka nol di depan, yang tampaknya tidak diingkari dalam pertanyaan awal atau komentarnya.

LegionMammal978
sumber
Saat menggunakan using System;, Anda tidak perlu System.Randomdua kali, tetapi hanya Random, kan?
Charlie
@Charlie Ini adalah fungsi, jadi saya tidak bisa menggunakan usingpernyataan. Itu hanya akan menghemat 1 char.
LegionMammal978
1
Anda dapat menghemat 1 char dengan menghapus spasi di -1E6, 1E6+1.
ProgramFOX
2

Perl, 62 byte

print $n=int rand(20)-10;while($n&&rand>.1){print int rand 10}

Saya memiliki ide yang sama dengan @Hobbs, untuk menghasilkan digit pada satu waktu, tetapi kodenya tidak memenuhi persyaratan tambahan no-leading-zero. Menghasilkan digit pertama dan bukan hanya pertanda memecahkannya. Dan kecuali ada cara yang lebih pendek untuk keluar jika kita mencetak nol, atau cara yang lebih pendek untuk menghasilkan -9 ke 9, ini harus dilakukan untuk ukuran.

Dalam lingkaran shell: while perl -e '...'; do echo;done |less

Saya pikir ini adalah salah satu yang terpendek yang tidak memerlukan RAM yang tak terbatas untuk memenuhi masalah. Sebagai bonus, hasilnya tidak terlalu bias terhadap apa pun, dan runtime sangat cepat.

Saya mencoba menggunakan bitwise dan untuk menyimpan karakter dalam kondisi sementara, tapi saya pikir ini akhirnya menjadi benar lebih sering, sehingga loop berakhir lebih cepat. Akan membutuhkan lebih banyak karakter untuk menyesuaikan hal-hal lain untuk mengatasinya, untuk mempertahankan probabilitas menghasilkan abs (output)> 1M.

Peter Cordes
sumber
Bagus, Anda memeras beberapa hal yang tidak akan saya pikirkan :)
hobbs
1

Javascript (73)

Solusi ini menggunakan bahwa Anda dapat membuat angka dengan basis n dengan mengalikan angka sebelumnya dengan n dan menambahkan angka dalam basis n . Kami memiliki tambahan ..?..:..di sana untuk dapat membuat semua bilangan bulat negatif. Kode berikut harus diuji di konsol browser.

b=Math.round;c=Math.random;x=0;while(b(c()*99)){x*=b(c())?2:-2;x+=b(c())}

Probabilitas untuk mendapatkan integer> = 2^1(atau <= -(2^1)) sama dengan kemungkinan loop dijalankan 2 kali. Peluang terjadinya itu adalah (98/99)^2. Karena itu peluang untuk mendapatkan angka yang lebih besar dari 2^20(atau <= -(2^20)) adalah (98/99)^21 = 0.80881%. Ini semua dalam teori, dan dengan asumsi bahwa Math.random benar-benar acak. Jelas tidak.


Cuplikan menguji kode ini. Juga dengan cara yang lebih mudah dibaca.

Sumurai8
sumber
1
OP sekarang telah mengkonfirmasi bahwa Anda dapat mengasumsikan bahwa PRNG Anda benar-benar acak, bahkan jika tidak.
trichoplax
1

GolfScript, 20 byte

0{)8.?rand}do.2&(*4/

Ya, ini juga agak lambat.

Dibandingkan dengan bahasa-bahasa seperti CJam dan Pyth, GolfScript menderita kata kunci pembangkitan angka acak verbose ( rand). Untuk mengatasi cacat ini, saya perlu menemukan cara untuk menggunakannya hanya sekali.

Kode ini bekerja dengan berulang kali memilih angka acak antara 0 dan 8 8 −1 = 16.777.215 inklusif, dan menambah penghitung hingga bilangan acak menjadi 0. Nilai penghitung yang dihasilkan memiliki distribusi geometris dengan median sekitar -1 / log 2 (1 - 1/8 8 ) ≈ 11.629.080, sehingga memenuhi tes "lebih dari 1.000.000 setidaknya 50% dari waktu".

Sayangnya, angka acak yang dihasilkan selalu benar-benar positif. Jadi, ekstra.2&(*4/ diperlukan untuk menjadikannya negatif atau nol. Ia bekerja dengan mengekstraksi bit terendah nomor kedua (yang dengan demikian 0 atau 2), menurunkannya menjadi -1 atau 1, mengalikannya dengan angka asli, dan membagi hasilnya dengan 4 (untuk menghilangkan dua bit terendah, yang sekarang berkorelasi dengan tanda, dan juga untuk memungkinkan hasilnya menjadi nol). Bahkan setelah pembagian dengan 4, nilai absolut dari angka acak masih memiliki median -1 / log 2 (1 - 1/8 8 ) / 4 ≈ 2.907.270, sehingga masih melewati tes 50%.

Ilmari Karonen
sumber
1

JavaScript, 81 byte

Kode ini memenuhi semua aturan:

  • Keluarkan bilangan bulat apa pun dengan probabilitas positif
  • Bilangan bulat keluaran di luar kisaran +/- 1000000 dengan kemungkinan setidaknya 50%
  • Tidak ada yang memimpin 0dalam output

Sebagai bonus, algoritma ini berjalan dengan kompleksitas waktu O (log 10 n) sehingga mengembalikan integer hampir secara instan.

for(s="",r=Math.random;r()>.1;s+=10*r()|0);r(s=s.replace(/^0*/,"")||0)<.5?"-"+s:s

Ini mengasumsikan lingkungan REPL. Coba jalankan kode di atas di konsol browser Anda, atau gunakan snipet stack di bawah ini:

D.onclick = function() {
  for(s="", r=Math.random;r()>.1; s+=10*r()|0);
  P.innerHTML += (r(s=s.replace(/^0*/,"") || 0) <.5 ?"-" + s : s) + "<br>"
}
<button id=D>Generate a random number</button><pre id=P></pre>

Algoritma :

  • Terus tambahkan angka acak ke string shingga a Math.random() > 0.1.
  • Berdasarkan Math.random() > 0.5, buat angka negatif (dengan mengawali string sdengan -).

Algoritma ini tidak memiliki distribusi seragam di semua bilangan bulat. Integer dengan jumlah digit yang lebih tinggi lebih kecil kemungkinannya daripada yang lebih rendah. Di setiap untuk iterasi loop, ada kemungkinan 10% bahwa saya akan berhenti pada digit saat ini. Saya hanya harus memastikan bahwa saya berhenti setelah 6 digit lebih dari 50% dari waktu.

Persamaan ini oleh @nutki menjelaskan nilai maksimum persentase peluang berhenti berdasarkan kondisi di atas:

1 - 50%^(1/6) ≈ 0.11

Dengan demikian 0,1 berada dalam jangkauan untuk memenuhi ketiga aturan pertanyaan.

Pengoptimal
sumber
Ada beberapa hal yang membingungkan saya tentang jawaban ini. Pernahkah Anda berasumsi bahwa Math.random () menghasilkan distribusi angka acak yang seragam, karena spesifikasi menyatakan bahwa itu tergantung pada implementasi. Dengan asumsi bahwa itu adalah distribusi yang seragam, P (Math.random ()> 0,1) = 0,9 sehingga ada kemungkinan besar bahwa itu akan berakhir antara setiap iterasi. Implementasi algoritme Anda berjalan pada Firefox 34.0 Ubuntu memberi saya probabilitas ~ 0,47 (<0,5) setiap kali saya mengujinya: jsfiddle.net/WK_of_Angmar/dh8gq4pb
Wk_of_Angmar
Juga, bagaimana Anda berhasil menghitung kompleksitas waktu untuk suatu algoritma tanpa input?
Wk_of_Angmar
1

TI-BASIC, 14 byte

1-2int(2rand:randNorm(AnsE6,9

Mirip dengan jawaban R @ ssdecontrol, ini diambil dari distribusi Gaussian dengan rata-rata -1.000.000 atau 1.000.000, dipilih secara acak, dan standar deviasi 9. Distribusi tidak terikat sehingga secara teori ini dapat menghasilkan bilangan bulat apa pun.

Penjelasan :

1-2int(2rand     - get a random integer 0 or 1, then multiply by 2 and subtract 1
:                - this gives the number 1 or -1 (with equal probability) to Ans
randNorm(AnsE6,9 - displays Gaussian distribution with mean (Ans * 1,000,000) and std. dev. 9
Timtech
sumber
Tapi bisakah itu menghasilkan "2" atau "-2"?
kennytm
Ya tentu saja. tibasicdev.wikidot.com/randnorm
Timtech
1
OK membaca kode yang salah (pikiran :berarti "cetak" karena bagaimana penjelasannya disajikan). Tapi bisakah itu menghasilkan angka lebih dari 20 digit?
kennytm
Adakah integer panjang yang arbitrer dimungkinkan sebagai output? Bukankah ini dibatasi oleh kisaran randNorm?
Pengoptimal
"Distribusi tidak dibatasi sehingga secara teori ini dapat menghasilkan bilangan bulat apa pun." Tidak ada jangkauan.
Timtech
1

Bash, 66

LANG=C sed -r '/^-?(0|[1-9][0-9]*)$/q;s/.*/5000000/;q'</dev/random

Hampir selalu mencetak 50.000.000. Tetapi jika menemukan nomor yang valid /dev/random, ia akan mencetak nomor itu.

Dan ini lebih cepat:

LANG=C sed -r '/^-?(0|[1-9][0-9]*)$/q;s/.*/5000000/;q'</dev/urandom
jimmy23013
sumber
1
@ Opptizer Seharusnya lambat. Itu karena itu adalah sumber acak nyata. Tapi Anda bisa mengujinya dengan /dev/urandomyang kurang acak.
jimmy23013
@ Opptizer Bagaimana cara mengambil input manual? Ini membaca file, tetapi semuanya file.
Nit
@ Pengoptimal Saya tidak mengerti tujuan Anda.
Nit
membaca dari /dev/urandomdalam skrip shell pada dasarnya sama dengan memanggil rand()dalam bahasa lain. Meskipun jika Anda benar-benar menggunakan bash, bukan POSIX sh, Anda bisa mendapatkan nomor acak dari echo $RANDOM. wiki.ubuntu.com/DashAsBinSh memberi hexdump /dev/urandomsebagai yang setara untuk minimum-POSIX /bin/dash.
Peter Cordes
1

C ++, 95 byte

void f(){int d=-18,s=-1;while(s<9){d=(rand()%19+d+9)%10;cout<<d;s=9-rand()%10*min(d*d+s+1,1);}}

Diperluas:

void f() {
    int d=-18,s=-1;
    while(s<9) {
        d=(rand()%19+d+9)%10;
        cout<<d;
        s=9-rand()%10*min(d*d+s+1,1);
    }
}

Penjelasan:

Fungsi ini terus mencetak angka acak berurutan hingga sakelar nilai acak mengambil nilai yang diperlukan untuk menghentikan fungsi. d adalah variabel yang menjaga nilai digit berikutnya untuk dicetak. s adalah variabel sakelar yang mengambil nilai bilangan bulat acak dalam interval [0, 9], jika s == 9 maka tidak ada lagi digit yang dicetak dan funtion berakhir.

Variabel d dan s diinisialisasi untuk memberikan perlakuan khusus pada digit pertama (mengambilnya dari interval [-9, 9] dan jika digit pertama adalah nol maka fungsi harus diakhiri untuk menghindari memimpin nol). Nilai d dapat ditetapkan sebagai d = rand ()% 10 tetapi kemudian digit pertama tidak boleh negatif. d ditugaskan sebagai d = (rand ()% 19 + d + 9)% 10 dan diinisialisasi pada -18 sehingga nilai pertama dari d akan berkisar dari [-9, 9] dan nilai selanjutnya akan selalu berkisar dari [0 , 9].

Variabel s berkisar secara acak dari [0, 9], dan jika s sama dengan 9, fungsi berakhir, jadi setelah mencetak digit pertama yang berikutnya akan dicetak dengan probabilitas 90% (dengan asumsi rand () benar-benar acak, dan untuk memenuhi kondisi ketiga). s dapat dengan mudah ditetapkan sebagai s = rand ()% 10, namun, ada pengecualian, jika digit pertama adalah nol, fungsi harus diakhiri. Untuk menangani pengecualian tersebut, s telah ditetapkan sebagai s = 9-rand ()% 10 * min (d * d + s + 1,1) dan diinisialisasi sebagai -1. Jika digit pertama adalah nol, min akan mengembalikan 0 dan s akan sama dengan 9-0 = 9. Tugas variabel s akan selalu berkisar dari [0, 9], jadi pengecualian hanya dapat terjadi pada digit pertama.

Karakteristik (dengan asumsi rand () benar-benar acak)

  • Integer dicetak digit demi digit, dengan probabilitas tetap 90% untuk mencetak digit lain setelah mencetak yang terakhir.

  • 0 adalah bilangan bulat dengan peluang tertinggi untuk dicetak, dengan probabilitas sekitar 5,2%.

  • Probabilitas mencetak bilangan bulat pada interval [-10 ^ 6, 10 ^ 6] adalah sekitar 44% (perhitungan tidak ditulis di sini).

  • Bilangan bulat positif dan negatif dicetak dengan probabilitas yang sama (~ 47,4%).

  • Tidak semua digit dicetak dengan probabilitas yang sama. Misalnya: di tengah pencetakan bilangan bulat, jika digit terakhir adalah 5, digit 3 akan memiliki peluang yang sedikit lebih rendah untuk dicetak berikutnya. Secara umum, jika digit terakhir adalah d, digit (d + 18)% 10 akan memiliki peluang yang sedikit lebih rendah untuk dicetak berikutnya.

Contoh output (10 eksekusi)

-548856139437
7358950092214
507
912709491283845942316784
-68
-6
-87614261
0
-5139524
7

Process returned 0 (0x0)   execution time : 0.928 s
Press any key to continue.
Daniel Turizo
sumber
1

Bash, 42 byte

printf "%d\n" 0x$(xxd -p -l5 /dev/random)
/ dev / random pada OSX hanya byte acak, dan xxd -p -l5mengubah 5 karakter ascii menjadi hex, dan printfmengubahnya menjadi format desimal.

Camden
sumber
0

Pyth , 11 byte

WOyG~ZtOT)Z

Catatan: program ini mungkin akan macet dengan kesalahan memori di komputer mana pun. Untuk mengujinya, coba ganti Gdengan string yang lebih pendek, seperti dalam kode ini, yang menghasilkan angka rata-rata sekitar 28000:

pyth -c 'WOy"abcdefghijklm"~ZtOUT)Z'

Kode ini berulang, menambahkan angka acak dari -1 hingga 8 Z, dengan probabilitas 2 ^ -26 keluar dari loop pada setiap pengulangan. Probabilitas 2 ^ -26 diperoleh dengan memilih elemen acak ( O) dari himpunan semua himpunan bagian ( y) dari alfabet ( G).

Detail & justifikasi teknis:

Probabilitas 2 ^ -26 berasal dari dua fakta:, yketika dipanggil pada sekuens, adalah fungsi power-set, sebuah susunan daftar semua himpunan bagian dari input. Karena input,, Gadalah 26 karakter, set daya ini, yGmemiliki 2 ^ 26 entri. OyGmemilih elemen acak dari 2 ^ 26 entri itu. Salah satu dari entri itu, string kosong, akan dievaluasi sebagai falsy ketika diteruskan keW , while. Oleh karena itu, ada kemungkinan 2 ^ -26 keluar dari loop setiap kali.

Dalam jumlah tetap dari siklus loop K, probabilitas mendapatkan angka K * 3.5 + m dan mendapatkan K * 3.5 - m adalah sama, karena setiap urutan penambahan yang mencapai satu total dapat dibalik, -1 -> 8, 0 -> 7, dll., Untuk mencapai yang lain. Selain itu, angka yang lebih dekat ke K * 3,5 jelas lebih mungkin daripada angka yang lebih jauh. Dengan demikian, jika K> 2000000 / 3.5 = 571428.5 kemungkinan mendapatkan angka lebih dari 10.00000 lebih besar dari 75%, karena beberapa hasil di atas angka itu dapat dimasukkan ke dalam korespondensi satu-ke-satu dengan semua hasil di bawah ini yang angka, dan bagian atas kurang dari setengah, dapat dimasukkan ke dalam korespondensi satu-ke-satu dengan yang di bawah 1000000. Kemungkinan mendapatkan setidaknya 571429 loop adalah (1-2 ^ -26) ^ 571429, yang tidak ada kurang dari (1-2 ^ -26 * 571429), perkiraan berapa kali meninggalkan loop pada 571429 percobaan pertama, yaitu 99,1%. Jadi, pada 99,1% atau lebih uji coba, ada kemungkinan 75% atau lebih untuk mendapatkan setidaknya 10.00000, sehingga ada lebih dari 50% peluang untuk mendapatkan lebih dari 10.00000.

Kode ini bergantung pada perilaku di Omana bug diperkenalkan secara tidak sengaja 3 hari yang lalu dan diperbaiki hari ini. Ini harus bekerja pada versi Pyth 3 apa pun dari sebelum 22 Desember, atau setelah hari ini. Kode berikut ini setara, dan selalu berfungsi:

WOyG~ZtOUT)Z
isaacg
sumber
Apa yang terjadi dengan kompiler online?
Pengoptimal
@Optimizer Masalah dengan situs web, saya akan mengatasinya.
isaacg
Ah .. keren. Ingin bekerja pada terjemahan Pyth jawaban CJam saya kemarin dan menemukan bahwa ia memberikan 404.
Pengoptimal
0

Java, 113 byte

void g(){String a=Math.random()>0?"10":"01";for(;Math.random()>0;)a+=(int)(Math.random()*2);System.out.print(a);}

Program ini mencetak angka biner ke aliran keluaran standar. Anda mungkin harus menunggu beberapa saat karena probabilitas untuk mengakhiri angka (atau positif) adalah sekitar 0. Gagasan bahwa nilai absolut dari angka yang dihasilkan kurang dari 1 juta adalah lucu, namun dimungkinkan.

Tidak Disatukan:

void g(){
    String a=Math.random()>0?"10":"01";             //Make sure there are no trailing zeroes.
    for(;Math.random()>0;)a+=(int)(Math.random()*2);//Add digits
    System.out.print(a);                            //Print
}

Contoh output: Akan memposting ketika angka selesai dibuat.

TheNumberOne
sumber
0

Java (JDK) , 140 127 byte

()->{int i;var o=System.out;for(o.print(i=(int)(19*Math.random())-10);i!=0&Math.random()<.9;)o.print((int)(11*Math.random()));}

-13 bytes dengan menyelinap lebih banyak logika ke header loop - terima kasih kepada @ceilingcat

Cobalah online!

Sara J
sumber