Math.random ของ JavaScript สุ่มอย่างไร


117

เป็นเวลา 6 ปีที่ฉันมีหน้าสร้างตัวเลขสุ่มบนเว็บไซต์ของฉัน เป็นผลการค้นหาแรกหรือครั้งที่สองใน Google สำหรับ "ตัวสร้างตัวเลขสุ่ม" และถูกนำมาใช้ในการตัดสินใจนับสิบหากไม่ใช่การแข่งขันและภาพวาดหลายร้อยรายการในฟอรัมสนทนาและบล็อก (ฉันรู้เพราะฉันเห็นผู้อ้างอิงใน บันทึกเว็บและมักจะไปดู)

วันนี้มีคนส่งอีเมลมาบอกฉันว่ามันอาจจะไม่สุ่มอย่างที่ฉันคิด เธอลองสร้างตัวเลขสุ่มที่มีขนาดใหญ่มาก (เช่นระหว่าง 1 ถึง 10000000000000000000) และพบว่าตัวเลขเหล่านี้เป็นตัวเลขเดียวกันเกือบตลอดเวลา อันที่จริงฉันห่อฟังก์ชั่นเป็นวงเพื่อให้สามารถสร้างตัวเลขได้หลายพันตัวและแน่นอนว่าสำหรับตัวเลขจำนวนมากการเปลี่ยนแปลงนั้นมีขนาดประมาณ 2 คำสั่งเท่านั้น

ทำไม?

นี่คือเวอร์ชันวนซ้ำเพื่อให้คุณสามารถทดลองใช้ด้วยตัวคุณเอง:

http://andrew.hedges.name/experiments/random/randomness.html

ซึ่งรวมถึงการใช้งานที่ตรงไปตรงมาจากMozilla Developer Networkและโค้ดบางส่วนจากปี 1997 ที่ฉันได้กวาดหน้าเว็บที่ไม่มีอยู่แล้ว ("Central Randomizer 1.3" ของ Paul Houle) ดูแหล่งที่มาเพื่อดูว่าแต่ละวิธีทำงานอย่างไร

ฉันได้อ่านที่นี่และที่อื่น ๆเกี่ยวกับMersenne Twister สิ่งที่ฉันสนใจคือเหตุใดจึงไม่มีการเปลี่ยนแปลงที่มากขึ้นในผลลัพธ์จากฟังก์ชันMath.randomในตัวของ JavaScript ขอบคุณ!


"sarnath'd" เช่นเดียวกับในการตีต่อยหรือในกรณีนี้คำตอบ
maetl

5
หากคุณกำลังมองหาคำตอบสำหรับคำถามในชื่อเรื่องโปรดดูstackoverflow.com/questions/2344312/…
Andrew B.

คำตอบ:


182

ระบุตัวเลขระหว่าง 1 ถึง 100

  • 9 มี 1 หลัก (1-9)
  • 90 มี 2 หลัก (10-99)
  • 1 มี 3 หลัก (100)

ระบุตัวเลขระหว่าง 1 ถึง 1,000

  • 9 มี 1 หลัก
  • 90 มี 2 หลัก
  • 900 มี 3 หลัก
  • 1 มี 4 หลัก

และอื่น ๆ

ดังนั้นหากคุณเลือกแบบสุ่มตัวเลขที่เลือกส่วนใหญ่จะมีจำนวนหลักเท่ากันเนื่องจากค่าที่เป็นไปได้ส่วนใหญ่มีจำนวนหลักเท่ากัน


11
ความคิดของคุณเกี่ยวกับความหมายแบบสุ่มที่มีความหมายอย่างสมบูรณ์และกระจายอย่างสม่ำเสมอนั้นน่าสนใจ ...

19
@ R.Pate - การสร้างตัวเลขสุ่มไม่ได้ใช้ประโยชน์มากนักเว้นแต่จะมีการกระจายอย่างเท่าเทียมกันในระดับยาว
annakata

3
อ่านอีกครั้ง. @David ระบุเฉพาะตัวเลขที่อยู่ระหว่างขีด จำกัด เท่านั้นไม่ใช่ผลของการเลือก N สุ่มตัวเลข ฉันยอมรับว่าการตั้งชื่อนั้นทำให้เข้าใจผิด
nikc.org

3
สำหรับบันทึกนี้ฉันโหวตทั้งคำตอบนี้และคำตอบของ @jwoolard ฉันเลือกคำตอบนี้เป็นคำตอบที่ยอมรับเพราะตัวอย่างทำให้ชัดเจนเหมือนคริสตัลว่าทำไมการกระจายของตัวเลขจึงเบ้เป็นตัวเลขที่มีตัวเลขมากกว่า
Andrew Hedges

1
@ andrew-hedges ค่อนข้างถูก - นี่คือคำตอบที่ชัดเจนกว่า แต่ขอบคุณ :)
jwoolard

56

ผลลัพธ์ของคุณเป็นจริง หากตัวเลขสุ่มมีการกระจายอย่างสม่ำเสมอในช่วง 1 ถึง 10 ^ n คุณคาดว่าประมาณ 9/10 ของตัวเลขจะมี n หลักและอีก 9/100 จะมี n-1 หลัก


8
เผง การกระจายของจำนวนหลักคาดว่าจะเบ้ อย่างไรก็ตามการกระจายของบันทึกของจำนวนหลัก shoudl จะเหมือนกัน
Noldorin

45

มีการสุ่มประเภทต่างๆ Math.randomให้การแจกแจงตัวเลขที่สม่ำเสมอ

หากคุณต้องการลำดับขนาดที่แตกต่างกันฉันขอแนะนำให้ใช้ฟังก์ชันเลขชี้กำลังเพื่อสร้างสิ่งที่เรียกว่าการกระจายกฎอำนาจ :

function random_powerlaw(mini, maxi) {
    return Math.ceil(Math.exp(Math.random()*(Math.log(maxi)-Math.log(mini)))*mini)
}

ฟังก์ชันนี้ควรให้ตัวเลข 1 หลักเท่ากับตัวเลข 2 หลักและตัวเลข 3 หลักโดยประมาณ

นอกจากนี้ยังมีการแจกแจงอื่น ๆ สำหรับตัวเลขสุ่มเช่นการแจกแจงปกติ (เรียกอีกอย่างว่าการแจกแจงแบบเกาส์)


ด้วยอัลกอริทึมนี้ฉันใส่minimum = 1และmaximum = 10และบางครั้งก็จะได้ 11 เป็นผลลัพธ์ คุณอาจตั้งใจจะใช้Math.floorแทนMath.round
Sam Eaton

1
ทำไมมันถึงได้ผล? มันเปลี่ยนการกระจายสม่ำเสมอเป็นการแจกแจงเลขชี้กำลังหรือไม่?
shinzou

@shinzou ฉันถามในmath.stackexchangeและได้สูตรที่แตกต่างกันเล็กน้อยเป็นคำตอบ ฉันเปลี่ยนรหัสเพื่อแสดงสูตรที่ได้มาจากคณิตศาสตร์จาก math.stackexchange
Christian

21

ดูสุ่มอย่างสมบูรณ์แบบสำหรับฉัน! (คำแนะนำ: ขึ้นอยู่กับเบราว์เซอร์)

โดยส่วนตัวแล้วฉันคิดว่าการใช้งานของฉันจะดีกว่าแม้ว่าฉันจะขโมยมันไปจากXKCDแต่ใครก็ตามที่ควรได้รับการยอมรับ:

function random() {
  return 4; // Chosen by a fair dice throw. Guaranteed to be random.
}

19
+1 สำหรับการกล่าวถึงเบราว์เซอร์ขึ้นอยู่กับ -1 สำหรับการยืม xkcd โดยไม่ต้องเชื่อมโยง

จำเป็นหรือไม่เนื่องจากเป็น xkcd จึงได้รับการระบุแหล่งที่มา :)
Arafangion

2
OT: รู้สึกประหลาดใจและดีใจที่ "XKCD" เป็นคำตอบของคำถาม University Challenge สัปดาห์นี้: D
Matt Sach

2
Bergi: ลิงก์โดยตรงไม่เพียงพอเหรอ?
Arafangion

ฉันคิดว่าพวกเขาหมายถึงเรื่องตลกที่อ้างถึงไม่ถูกต้อง ("random = 4;" แทนที่จะเป็น "return 4;")
Eren Tantekin

18

กระดาษต่อไปนี้อธิบายถึงวิธีการ Math.random () ในเว็บเบราเซอร์ที่สำคัญคือ (UN) ที่เชื่อถือได้: "การติดตามผู้ใช้ชั่วคราวในเบราว์เซอร์ที่สำคัญและการรั่วไหลของข้อมูลข้ามโดเมนและการโจมตี" โดยท่ามกลางไคลน์ (2008) ไม่ได้แข็งแกร่งไปกว่าฟังก์ชัน PRNG ในตัวของ Java หรือ Windows ทั่วไป

ในทางกลับกันการใช้ SFMT ของช่วงเวลา 2 ^ 19937-1 ต้องใช้สถานะภายใน 2496 ไบต์ที่คงไว้สำหรับลำดับ PRNG แต่ละลำดับ บางคนอาจมองว่านี่เป็นต้นทุนที่ไม่อาจให้อภัยได้


1
+1: กระดาษที่กล่าวถึงนั้นยอดเยี่ยมมากเกินกว่าคำถามเดิม
Roland Illig

6

หากคุณใช้ตัวเลขเช่น 10000000000000000000 คุณจะเกินความแม่นยำของ Javascript ประเภทข้อมูลที่ใช้ โปรดทราบว่าตัวเลขทั้งหมดที่สร้างขึ้นลงท้ายด้วย "00"


1
นั่นไม่ใช่ปัญหาของเขาในกรณีนี้
Joey

3
@Johannes - มันเป็นปัญหาอย่างหนึ่งของเขา :)
annakata

การกระจายของ IEE754 ไม่เท่ากัน บางทีคุณอาจแทน 0 ถึง 999 โดยเพิ่มทีละสองและมีความแม่นยำเพียงพอสำหรับสิ่งนั้นคุณจึงสังเกตเห็นการแจกแจงแบบสม่ำเสมอในช่วงนั้นหากคุณเลือกตัวเลขหลาย ๆ ครั้ง 10% จะเป็นสองหลักและ 90% สามหลัก เมื่อคุณเริ่มตีตัวเลขที่สูงมาก ๆ การเพิ่มจะเกิน 1 คุณอาจจะสามารถก้าวจากล้านล้านพันล้านไปเป็นล้านล้านพันล้านหนึ่งพันไม่ใช่หนึ่งล้านล้านพันล้าน แม้ว่าจะมีตัวเลข / สเกลเล็ก ๆ แต่ผลกระทบนี้จะมีน้อยมากถึงไม่มีอยู่จริง เอฟเฟกต์ขนาดจะมีผลกระทบมากขึ้น
jgmjgm

5

ฉันพยายาม JS ตัวสร้างเลขสุ่มเทียมในความโกลาหลเกม

สามเหลี่ยมSierpińskiของฉันบอกว่ามันค่อนข้างสุ่ม: เศษส่วน


2
คุณช่วยแบ่งปันรหัสสามเหลี่ยมที่นี่และ jsfiddle / jsbin เพื่อให้เราสามารถตรวจสอบได้อย่างง่ายดายในทางปฏิบัติสำหรับเบราว์เซอร์ต่างๆหรือไม่?
FabrícioMatté

1
โอเค แต่ขอเวลาฉันสักสองสามวันเพราะฉันต้องแปลโค้ดเป็นภาษาอังกฤษ ตอนนี้เป็นภาษาโปลิช - อังกฤษและฉันมีงานเยอะมาก
zie1ony

1
@ zie1ony สองสามวันจะหมดแล้ว
trusktr

1
usp :( ทำงานทำงานทำงานลิงก์: kubaplas.vot.pl/green/fractalพารามิเตอร์แรกคือ nr ของจุดยอดค่าที่สองคือจุดตัด (จาก 0 ถึง 1) ของส่วนของเส้นตรงเพียงแค่ทดลอง
zie1ony

4
ลิงก์ตาย - อาจเป็น repo Github แทน?
Mark K Cowan

3

ถ้าคุณสร้างตัวเลขได้ถึง 1e6 คุณจะได้ตัวเลขทั้งหมดที่มีความน่าจะเป็นเท่ากันโดยประมาณ นั่นหมายความว่าคุณมีโอกาสเพียงหนึ่งในสิบที่จะได้ตัวเลขที่น้อยกว่าหนึ่งหลัก โอกาสหนึ่งในร้อยที่จะได้ตัวเลขสองหลักน้อยลง ฯลฯ ฉันสงสัยว่าคุณจะเห็นความแตกต่างอย่างมากเมื่อใช้ RNG อื่นเพราะคุณมีการแจกแจงแบบสม่ำเสมอในตัวเลขไม่ใช่ลอการิทึม


0

ตัวเลขที่ไม่สุ่มกระจายอย่างสม่ำเสมอตั้งแต่ 1 ถึง N มีคุณสมบัติเหมือนกัน โปรดทราบว่า (ในบางแง่) มันเป็นเรื่องของความแม่นยำ การแจกแจงแบบสม่ำเสมอบน 0-99 (เป็นจำนวนเต็ม) มี 90% ของตัวเลขที่มีสองหลัก การแจกแจงแบบสม่ำเสมอบน 0-999999 มี 905 ของตัวเลขที่มีห้าหลัก

ชุดตัวเลขใด ๆ (ภายใต้เงื่อนไขที่ไม่ จำกัด เกินไป) มีความหนาแน่น เมื่อมีคนต้องการพูดคุยเกี่ยวกับตัวเลข "สุ่ม" ควรระบุความหนาแน่นของตัวเลขเหล่านี้ (ตามที่ระบุไว้ข้างต้น) ความหนาแน่นทั่วไปคือความหนาแน่นสม่ำเสมอ มีอื่น ๆ : ความหนาแน่นเลขชี้กำลังความหนาแน่นปกติ ฯลฯ เราต้องเลือกความหนาแน่นที่เกี่ยวข้องก่อนที่จะเสนอตัวสร้างตัวเลขสุ่ม นอกจากนี้ตัวเลขที่มาจากความหนาแน่นหนึ่งมักจะเปลี่ยนไปเป็นความหนาแน่นอื่นได้อย่างง่ายดายด้วยวิธีการที่เป็นฟันผุ

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