Bisakah random.uniform (0,1) menghasilkan 0 atau 1?

9

Dalam dokumentasi dikatakan bahwa ada peluang yang uniform(0,1)dapat menghasilkan nilai 0dan 1.

Saya telah menjalankan uniform(0, 1)10.000 kali, tetapi tidak pernah menghasilkan nol. Bahkan dalam kasus uniform(0, 0.001).

Bisakah random.uniform(0,1)pernah menghasilkan 0atau 1?

Venkatesh Gandi
sumber
3
Secara teori itu mungkin, tetapi secara praktis tidak akan pernah terjadi. Secara matematis, variabel acak seragam standar dapat mengambil pada setiap nilai dalam interval 0 sampai 1. jika X ~ U(0,1), maka P(X=x)adalah hampir pasti 0, untuk semua nilai x. (Ini karena ada banyak kemungkinan nilai dalam interval.) Jika Anda mencari tepat 0 atau 1, Anda harus menggunakan fungsi yang berbedarandom.choice
petak
1
@pult hampir pasti memiliki arti yang sangat spesifik dalam matematika, yang tidak benar-benar masuk akal di sini karena kita memiliki distribusi diskrit bukan interval yang berkesinambungan. Hanya ada sejumlah pelampung yang terbatas antara 0 dan 1.
wim
2
@ pult Jadi mengapa Anda berbicara secara matematis ketika OP bertanya tentang implementasi random.uniform?
wim
1
Jika dokumentasi yang akurat, aku agak ingin tahu bagaimana itu dibuat untuk kemungkinan menghasilkan baik 0 dan 1. Sepertinya [0, 1) akan menjadi jauh lebih mudah (yang adalah bagaimana Math.random()bekerja dalam JavaScript, misalnya).
Ry-
1
50 poin hadiah untuk orang pertama yang mengirim benih acak yang menghasilkan random.uniform(0, 1)0 pada panggilan pertama
wim

Jawaban:

13

uniform(0, 1)dapat menghasilkan 0, tetapi tidak akan pernah menghasilkan 1.

The dokumentasi memberitahu Anda bahwa endpoint b dapat dimasukkan dalam nilai-nilai yang dihasilkan:

Nilai titik akhir bmungkin atau mungkin tidak termasuk dalam rentang tergantung pada pembulatan titik-mengambang dalam persamaan a + (b-a) * random().

Jadi untuk uniform(0, 1), formula 0 + (1-0) * random(), disederhanakan 1 * random(), harus mampu menghasilkan dengan 1tepat. Itu hanya akan terjadi jika random.random()1.0 exactly. However,acak () *never* produces1.0`.

Mengutip random.random()dokumentasi :

Kembalikan nomor floating point acak berikutnya dalam kisaran [0,0, 1.0).

Notasi [..., ...)berarti bahwa nilai pertama adalah bagian dari semua nilai yang mungkin, tetapi yang kedua tidak. random.random()akan paling nilai produk sangat dekat dengan 1.0. floatJenis Python adalah nilai floating point IEEE 754 base64 , yang mengkodekan sejumlah fraksi biner (1/2, 1/4, 1/5, dll.) Yang membentuk nilai, dan nilai yang random.random()dihasilkan hanyalah jumlah dari suatu pemilihan acak dari 53 fraksi tersebut dari 2 ** -1(1/2) hingga 2 ** -53(1/9007199254740992).

Namun, karena dapat menghasilkan nilai yang sangat dekat 1.0, bersama dengan kesalahan pembulatan yang terjadi ketika Anda mengalikan nubmers floating point, Anda dapat menghasilkan buntuk beberapa nilai adan b. Tetapi 0dan 1tidak di antara nilai-nilai.

Catatan yang random.random() dapat menghasilkan 0,0, jadi aselalu termasuk dalam nilai yang mungkin untuk random.uniform()( a + (b - a) * 0 == a). Karena ada 2 ** 53nilai berbeda yang random.random()dapat menghasilkan (semua kemungkinan kombinasi dari 53 pecahan biner), hanya ada 2 ** 53peluang 1 in (jadi 1 dalam 9007199254740992) yang pernah terjadi.

Jadi nilai tertinggi yang random.random()dapat dihasilkan adalah 1 - (2 ** -53); cukup pilih nilai yang cukup kecil untuk b - amemungkinkan pembulatan menendang ketika dikalikan dengan random.random()nilai yang lebih tinggi . Semakin kecil b - a, semakin besar kemungkinan hal itu terjadi:

>>> import random, sys
>>> def find_b():
...     a, b = 0, sys.float_info.epsilon
...     while random.uniform(a, b) != b:
...         b /= 2
...     else:
...         return b
...
>>> print("uniform(0, {0}) == {0}".format(find_b()))
...
uniform(0, 4e-323) == 4e-323

Jika Anda menekan b = 0.0, maka kami telah membagi 1023 kali, nilai di atas berarti kami beruntung setelah 1019 divisi. Nilai tertinggi yang saya temukan sejauh ini (menjalankan fungsi di atas dalam satu lingkaran dengan max()) adalah 8.095e-320(1008 divisi), tetapi mungkin ada nilai yang lebih tinggi. Ini semua adalah permainan kebetulan. :-)

Hal ini juga dapat terjadi jika tidak ada banyak langkah terpisah antara adan b, seperti kapan adan bmemiliki eksponen yang tinggi dan mungkin tampak jauh lebih jauh. Nilai titik apung masih hanya perkiraan, dan jumlah nilai yang dapat dikodekannya terbatas. Misalnya, hanya ada 1 fraksi biner perbedaan antara sys.float_info.maxdan sys.float_info.max - (2 ** 970), sehingga ada kemungkinan 50-50 random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max)menghasilkan sys.float_info.max:

>>> a, b = sys.float_info.max - (2 ** 970), sys.float_info.max
>>> values = [random.uniform(a, b) for _ in range(10000)]
>>> values.count(sys.float_info.max)  # should be roughly 5000
4997
Martijn Pieters
sumber
5

"Beberapa kali" tidak cukup. 10.000 tidak cukup. random.uniformmemilih dari antara 2 ^ 53 (9.007.199.254.740.992) nilai yang berbeda. Anda tertarik pada keduanya . Dengan demikian, Anda harus berharap untuk menghasilkan beberapa nilai acak kuadriliun sebelum mendapatkan nilai yang tepat 0 atau 1. Jadi itu mungkin, tetapi sangat mungkin Anda tidak akan pernah mengamatinya.

hobbs
sumber
2
Karena uniform(0, 1)tidak mungkin menghasilkan 1sebagai hasilnya. Itu karena fungsi hanya didefinisikan sebagai def uniform(a, b): return a + (b - a) * random()dan random()tidak pernah dapat menghasilkan 1.0.
Martijn Pieters
2
@ MartijnPieters Saya yakin Anda benar, dan saya meningkatkan jawaban Anda. Saya curiga, tapi saya tidak yakin, dan itu terlepas dari dorongan utama jawaban saya, jadi saya biarkan :)
hobbs
1

Anda dapat mencoba dan membuat loop yang menghitung jumlah iterasi yang diperlukan untuk ditampilkan dengan tepat 0 (jangan).

Selanjutnya, seperti yang dinyatakan oleh Hobbs, jumlah nilai yang uniformlydijadikan sampel adalah 9.007.199.254.740.992. Yang berarti kemungkinan melihat 0 adalah tepat 1 / 9.007.199.254.740.992. Yang secara umum dan pembulatan berarti Anda akan membutuhkan rata-rata 10 quatrillion sampel untuk menemukan 0. Tentu saja Anda mungkin menemukannya dalam 10 upaya pertama Anda, atau tidak pernah.

Pengambilan sampel 1 tidak dimungkinkan karena interval yang ditentukan untuk nilai-nilai ditutup dengan tanda kurung, karenanya tidak termasuk 1.

Celius Stingher
sumber
1

Tentu. Anda sudah berada di jalur yang benar dengan mencoba uniform(0, 0.001)saja. Terus membatasi batas-batas yang cukup untuk mewujudkannya lebih cepat.

>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
0.0
wim
sumber