Random.uniform (0,1) có thể tạo 0 hoặc 1 không?


9

Trong tài liệu nói rằng có một cơ hội uniform(0,1)có thể tạo ra các giá trị01.

Tôi đã chạy uniform(0, 1)10000 lần, nhưng nó không bao giờ tạo ra số không. Ngay cả trong trường hợp uniform(0, 0.001).

Bao random.uniform(0,1)giờ có thể tạo ra 0hay 1?


3
Về mặt lý thuyết là có thể, nhưng thực tế sẽ không bao giờ xảy ra. Về mặt toán học, một biến ngẫu nhiên thống nhất tiêu chuẩn có thể đảm nhận bất kỳ giá trị trong khoảng từ 0 đến 1. nếu X ~ U(0,1), thì P(X=x)gần như chắc chắn 0, cho tất cả các giá trị của x. (Điều này là do có vô số giá trị có thể có trong khoảng.) Nếu bạn đang tìm kiếm chính xác 0 hoặc 1, bạn nên sử dụng một hàm khácrandom.choice
pault

1
@pault gần như chắc chắn có một ý nghĩa rất cụ thể trong toán học, điều này không thực sự có ý nghĩa ở đây vì chúng ta có một phân phối rời rạc không phải là một khoảng liên tục. Chỉ có một số hữu hạn các phao nổi giữa 0 và 1.
wim

2
@pault Vậy tại sao bạn lại nói một cách toán học khi OP hỏi về việc triển khai random.uniform?
Wim

1
Nếu tài liệu đó là chính xác, tôi hơi tò mò về cách nó được tạo ra để có thể tạo cả 0 và 1. Có vẻ như [0, 1) sẽ dễ dàng hơn rất nhiều ( Math.random()ví dụ như cách hoạt động trong JavaScript).
Ry-

1
50 điểm thưởng cho người đầu tiên gửi một hạt giống ngẫu nhiên mà làm random.uniform(0, 1)trả về một 0 trên cuộc gọi đầu tiên
wim

Câu trả lời:


13

uniform(0, 1)có thể sản xuất 0, nhưng nó sẽ không bao giờ sản xuất 1.

Các tài liệu hướng dẫn cho bạn biết rằng thiết bị đầu cuối b có thể được bao gồm trong giá trị sản xuất:

Giá trị điểm cuối bcó thể có hoặc không được bao gồm trong phạm vi tùy thuộc vào làm tròn điểm nổi trong phương trình a + (b-a) * random().

Vì vậy uniform(0, 1), công thức 0 + (1-0) * random(), được đơn giản hóa 1 * random(), sẽ phải có khả năng sản xuất 1chính xác. Điều đó sẽ chỉ xảy ra nếu random.random()là 1.0 exactly. However,ngẫu nhiên () *never* produces1.0`.

Trích dẫn random.random()tài liệu :

Trả về số dấu phẩy động ngẫu nhiên tiếp theo trong phạm vi [0,0, 1,0).

Ký hiệu [..., ...)có nghĩa là giá trị đầu tiên là một phần của tất cả các giá trị có thể, nhưng giá trị thứ hai thì không. random.random()nhiều nhất sẽ tạo ra các giá trị rất gần với 1.0. floatKiểu của Python là một giá trị dấu phẩy động cơ sở của IEEE 754 , mã hóa một số phân số nhị phân (1/2, 1/4, 1/5, v.v.) tạo nên giá trị và giá trị random.random()tạo ra chỉ đơn giản là tổng của một lựa chọn ngẫu nhiên 53 phân số như vậy từ 2 ** -1(1/2) đến 2 ** -53(1/9007199254740992).

Tuy nhiên, bởi vì nó có thể tạo ra giá trị rất gần 1.0, cùng với làm tròn lỗi xảy ra khi bạn nhân nổi nubmers điểm, bạn có thể tạo ra bcho một số giá trị của ab. Nhưng01không nằm trong số những giá trị đó.

Lưu ý rằng random.random() có thể tạo 0,0, vì vậy aluôn được bao gồm trong các giá trị có thể cho random.uniform()( a + (b - a) * 0 == a). Bởi vì có 2 ** 53các giá trị khác nhau random.random()có thể tạo ra (tất cả các kết hợp có thể có của 53 phân số nhị phân đó), chỉ có 1 trong2 ** 53 (vì vậy 1 trong 9007199254740992) có thể xảy ra.

Vì vậy, giá trị cao nhất có random.random()thể có thể tạo ra là 1 - (2 ** -53); chỉ cần chọn một giá trị đủ nhỏ b - ađể cho phép làm tròn để khởi động khi nhân với random.random()giá trị cao hơn . Càng nhỏ b - a, cơ hội xảy ra càng lớn:

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

Nếu bạn trúng b = 0.0, thì chúng tôi đã chia 1023 lần, giá trị trên có nghĩa là chúng tôi đã gặp may sau 1019 đơn vị. Giá trị cao nhất tôi tìm thấy cho đến nay (chạy hàm trên trong một vòng lặp với max()) là8.095e-320 (1008 đơn vị), nhưng có thể có giá trị cao hơn. Tất cả đều là trò chơi may rủi. :-)

Nó cũng có thể xảy ra nếu không có nhiều bước riêng biệt giữa ab, như khi nào abcó số mũ cao và do đó có thể xuất hiện xa. Các giá trị dấu phẩy động vẫn chỉ là xấp xỉ và số lượng giá trị chúng có thể mã hóa là hữu hạn. Ví dụ: chỉ có 1 phần nhị phân khác biệt giữa sys.float_info.maxsys.float_info.max - (2 ** 970), do đó, có 50-50 cơ hội random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max)tạo ra 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

5

"Vài lần" là không đủ. 10.000 không đủ. random.uniformchọn trong số 2 ^ 53 (9,007,199,254,740,992) giá trị khác nhau. Bạn quan tâm đến hai trong số họ. Do đó, bạn nên tạo ra một vài triệu triệu giá trị ngẫu nhiên trước khi nhận được giá trị chính xác bằng 0 hoặc 1. Vì vậy, điều đó là có thể, nhưng rất có khả năng bạn sẽ không bao giờ quan sát được nó.


2
Đối với uniform(0, 1)nó là không thể để sản xuất 1như là kết quả. Đó là bởi vì hàm được định nghĩa đơn giản là def uniform(a, b): return a + (b - a) * random()random()không bao giờ có thể tạo ra 1.0.
Martijn Pieters

2
@MartijnPieters Tôi tin rằng bạn đã đúng và tôi đã nâng cao câu trả lời của bạn. Tôi đã nghi ngờ rất nhiều, nhưng tôi không chắc, và nó nằm ngoài lực đẩy chính của câu trả lời của tôi, vì vậy tôi đã để nó như vậy :)
hobbs

1

Bạn có thể thử và tạo một vòng lặp đếm số lần lặp cần thiết để được hiển thị chính xác 0 (không).

Hơn nữa, như Hobbs đã nêu, lượng giá trị được uniformlylấy mẫu là 9,007,199,254,740,992. Điều đó có nghĩa là xác suất nhìn thấy 0 chính xác là 1 / 9,007,199,254,740,992. Điều đó nói chung và làm tròn có nghĩa là bạn sẽ cần trung bình 10 mẫu quatrillion để tìm 0. Tất nhiên bạn có thể tìm thấy nó trong 10 lần thử đầu tiên hoặc không bao giờ.

Không thể lấy mẫu 1 vì khoảng thời gian được xác định cho các giá trị được đóng bằng dấu ngoặc đơn, do đó không bao gồm 1.


1

Chắc chắn rồi. uniform(0, 0.001)Thay vào đó, bạn đã đi đúng hướng với việc thử . Chỉ cần tiếp tục hạn chế giới hạn đủ để làm cho nó xảy ra sớm hơn.

>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
0.0
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.