Random.uniform (0,1) สามารถสร้าง 0 หรือ 1 ได้หรือไม่?


9

ในเอกสารได้มีการกล่าวว่ามีโอกาสที่uniform(0,1)สามารถสร้างคุณค่าและ01

ฉันวิ่งได้uniform(0, 1)10,000 ครั้ง แต่มันไม่เคยสร้างศูนย์เลย uniform(0, 0.001)แม้ในกรณีของ

สามารถrandom.uniform(0,1)ที่เคยสร้าง0หรือ1?


3
อาจเป็นไปได้ในทางทฤษฎี แต่ในทางปฏิบัติจะไม่เกิดขึ้น ในทางคณิตศาสตร์ตัวแปรสุ่มชุดมาตรฐานสามารถใช้กับค่าใด ๆ ในช่วงเวลาของ 0 ถึง 1 ถ้าX ~ U(0,1)จากนั้นP(X=x)เป็นเกือบ 0 แน่นอนสำหรับค่าทั้งหมดของ x (นี่เป็นเพราะมีค่าที่เป็นไปได้มากมายในช่วงเวลา) หากคุณกำลังมองหา 0 หรือ 1 คุณควรใช้ฟังก์ชั่นที่แตกต่างกันตัวอย่างเช่นrandom.choice
pault

1
@pault เกือบจะมีความหมายที่เฉพาะเจาะจงอย่างมากในวิชาคณิตศาสตร์ซึ่งไม่สมเหตุสมผลจริง ๆ เนื่องจากเรามีการแจกแจงแบบแยกส่วนไม่ใช่ช่วงต่อเนื่อง มีเพียงจำนวน จำกัด ของลอยระหว่าง 0 และ 1 มี
Wim

2
@pault ดังนั้นทำไมคุณพูดคณิตศาสตร์เมื่อ OP จะถามเกี่ยวกับการดำเนินงานของrandom.uniform?
wim

1
ถ้าเอกสารนั้นถูกต้องฉันก็อยากรู้ว่ามันจะสร้างทั้ง 0 และ 1 ได้อย่างไรดูเหมือนว่า [0, 1) จะง่ายกว่าเยอะ ( Math.random()ยกตัวอย่างเช่น JavaScript ทำงานอย่างไร)
Ry-

1
รางวัล 50 คะแนนสำหรับคนแรกที่โพสต์เมล็ดสุ่มซึ่งจะrandom.uniform(0, 1)คืนค่า 0 ในการโทรครั้งแรก
wim

คำตอบ:


13

uniform(0, 1) สามารถผลิต 0แต่มันจะไม่เคย1ผลิต

เอกสารบอกคุณว่าปลายทางb จะถูกรวมอยู่ในค่าที่ผลิต:

ค่าสิ้นจุดอาจจะหรืออาจจะไม่ได้รวมอยู่ในช่วงขึ้นอยู่กับจุดลอยปัดเศษในสมการba + (b-a) * random()

ดังนั้นสำหรับuniform(0, 1)สูตรที่0 + (1-0) * random()ง่าย1 * random()ขึ้นจะต้องมีความสามารถในการผลิต1อย่างแน่นอน ที่จะเกิดขึ้นถ้าrandom.random()เป็น 1.0 exactly. However,สุ่ม () *never* produces1.0`

การอ้างถึงrandom.random()เอกสาร :

ส่งคืนตัวเลขทศนิยมแบบสุ่มถัดไปในช่วง [0.0, 1.0)

สัญกรณ์[..., ...)หมายความว่าค่าแรกเป็นส่วนหนึ่งของค่าที่เป็นไปได้ทั้งหมด แต่ค่าที่สองไม่ใช่ random.random()ประสงค์ที่มากที่สุดค่าการผลิตอย่างใกล้ชิด1.0เพื่อ floatชนิดของ Python คือค่าคะแนนลอยตัว IEEE 754 base64ซึ่งเข้ารหัสเศษส่วนไบนารีจำนวนหนึ่ง(1/2, 1/4, 1/5 ฯลฯ ) ที่ประกอบขึ้นเป็นค่าและค่าที่random.random()ผลิตนั้นเป็นผลรวมของ การสุ่มเลือกเศษส่วน 53 รายการดังกล่าวจาก2 ** -1(1/2) ถึง2 ** -53(1/9007199254740992)

แต่เพราะมันสามารถผลิตค่ามากใกล้เคียงกับ1.0ร่วมกับการปัดเศษข้อผิดพลาดที่เกิดขึ้นเมื่อคุณคูณลอย nubmers จุดคุณสามารถผลิตbสำหรับบางค่าของและa bแต่0และ1ไม่ได้อยู่ในค่าเหล่านั้น

โปรดทราบว่าrandom.random() สามารถผลิต 0.0 ดังนั้นaจะรวมอยู่ในค่าที่เป็นไปได้สำหรับrandom.uniform()( a + (b - a) * 0 == a) เสมอ เนื่องจากมี2 ** 53ค่าที่แตกต่างกันที่random.random()สามารถสร้าง (การรวมที่เป็นไปได้ทั้งหมดของ 53 เศษส่วนไบนารี) มีเพียง 1 ใน2 ** 53(ดังนั้น 1 ใน 9007199254740992) โอกาสที่เกิดขึ้น

ดังนั้นค่าได้สูงสุดที่random.random()สามารถผลิตเป็น1 - (2 ** -53); เพียงเลือกค่าเล็ก ๆ ที่เพียงพอb - aเพื่อให้สามารถปัดเศษเพื่อเตะเมื่อคูณด้วยrandom.random()ค่าที่สูงกว่า ที่มีขนาดเล็กb - aมีมากขึ้นโอกาสที่จะเกิดขึ้นว่า:

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

หากคุณเข้าชมb = 0.0เราได้แบ่ง 1,023 ครั้งค่าข้างต้นหมายความว่าเราโชคดีหลังจากหน่วยงาน 1,019 แห่ง ค่าสูงสุดที่ฉันพบจนถึงขณะนี้ (การเรียกใช้ฟังก์ชันข้างต้นในลูปด้วยmax()) คือ8.095e-320(1008 ดิวิชั่น) แต่อาจมีค่าสูงกว่า มันคือเกมแห่งโอกาส :-)

นอกจากนี้ยังสามารถเกิดขึ้นได้หากมีไม่กี่ขั้นตอนโดยสิ้นเชิงระหว่างaและbเช่นเมื่อaและbมี exponent สูงและดังนั้นอาจปรากฏเป็น appart ไกล ค่าจุดลอยตัวยังคงเป็นเพียงการประมาณและจำนวนค่าที่สามารถเข้ารหัสนั้นมี จำกัด ตัวอย่างเช่นมีเพียงเศษส่วนไบนารีที่แตกต่างกันเพียง 1 ส่วนเท่านั้นsys.float_info.maxและsys.float_info.max - (2 ** 970)ดังนั้นจึงมีโอกาส 50-50 random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max)สร้าง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

"หลายครั้ง" ไม่เพียงพอ 10,000 ไม่เพียงพอ random.uniformเลือกจากค่าที่แตกต่างระหว่าง 2 ^ 53 (9,007,199,254,740,992) คุณสนใจพวกเขาสองคน ดังนั้นคุณควรคาดหวังว่าจะสร้างหลาย ๆค่าสุ่มจำนวนสี่พันล้านก่อนที่จะได้รับค่าที่ตรงกับ 0 หรือ 1 ดังนั้นจึงเป็นไปได้ แต่มีโอกาสมากที่คุณจะไม่สังเกตเห็น


2
เพราะuniform(0, 1)มันเป็นไปไม่ได้ที่จะสร้าง1ผลที่ตามมา นั่นเป็นเพราะฟังก์ชั่นถูกกำหนดอย่างง่าย ๆdef uniform(a, b): return a + (b - a) * random()และrandom()ไม่สามารถสร้าง1.0ได้
Martijn Pieters

2
@MartijnPieters ฉันเชื่อว่าคุณถูกต้องและฉันได้ตอบคำถามของคุณ ฉันสงสัยมาก แต่ฉันก็ไม่แน่ใจและมันก็นอกเหนือไปจากแรงผลักดันหลักของคำตอบของฉันดังนั้นฉันจะปล่อยให้มันเป็น :)
hobbs

1

คุณสามารถลองสร้างลูปที่นับจำนวนการวนซ้ำที่ต้องการเพื่อให้แสดงเป็น 0 แน่นอน (ไม่)

นอกจากนี้ตามที่ฮอบส์ระบุไว้จำนวนของค่าที่ถูกuniformlyสุ่มตัวอย่างคือ 9,007,199,254,740,992 ซึ่งหมายความว่าความน่าจะเป็นที่จะเห็น 0 นั้นเท่ากับ 1 / 9,007,199,254,740,992 ซึ่งในแง่ทั่วไปและการปัดเศษขึ้นหมายความว่าคุณจะต้องเฉลี่ย 10 ล้านตัวอย่างเพื่อหาค่า 0 แน่นอนว่าคุณอาจพบมันใน 10 ครั้งแรกหรือไม่เคยทำเลย

การสุ่มตัวอย่าง a 1 เป็นไปไม่ได้เนื่องจากช่วงเวลาที่กำหนดไว้สำหรับค่านั้นปิดด้วยวงเล็บดังนั้นจึงไม่รวม 1


1

แน่ใจ คุณอยู่ในเส้นทางที่ถูกต้องแล้วและพยายามuniform(0, 0.001)แทน เพียงแค่ จำกัด ขอบเขตอย่างเพียงพอเพื่อให้มันเกิดขึ้นเร็วขึ้น

>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
0.0
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.