Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Mastering Random Number Generation ใน Ruby: Techniques & Best Practices

Random numbers มีประโยชน์สำหรับหลาย purposes เช่น gaming, encryption และ building simulations ทางเทคนิค computers ไม่สามารถ generate random numbers ได้เพียงด้วย computation เพียงอย่างเดียว เป็น fundamentally impossible ที่จะ produce truly random numbers บน deterministic device ใดๆ สิ่งที่ดีที่สุดคือ pseudorandom numbers stream ของ numbers ที่ดูเหมือนถูก generate randomly

ในบทความนี้ เราจะดู various ways ที่คุณสามารถ generate random numbers ใน Ruby ได้

Generating Random Numbers ด้วย Kernel#rand

เริ่มต้นด้วยการ generate random numbers ด้วย method rand เมื่อ method ถูกเรียกโดยไม่มี arguments มันคืน float ที่ greater than หรือ equal to 0.0 และ less than 1.0

rand() > 0.7308136972953823

เพื่อได้ integer คุณส่ง integer ให้ function Function จะคืน random integer value ที่ greater than หรือ equal to 0 และ less than integer ที่ส่งให้ function ทุกครั้งที่รันต่อไปนี้ คุณจะได้ number ระหว่าง 0 และ 7

rand(8) > 5

สำหรับ random number ภายใน particular range ส่ง Range ให้ rand

ตัวอย่างต่อไปใช้ inclusive Range generate random numbers จาก lower limit (1) ถึง (และรวม) upper limit (10)

rand(1..10) > 6

ตัวอย่างถัดไปใช้ non-inclusive Range generate random numbers จาก lower limit ถึง (แต่ไม่รวม) upper limit

rand(1...10) > 9

Range ยังสามารถเป็นระหว่าง floating point values ได้

rand(1.5..3.0) > 1.7494305393711571

คุณยังสามารถใช้ negative range limits กับ rand ได้

rand(-5..-1) > -5

การส่ง single negative numbers อาจให้ surprising results ตามด้านล่าง

rand(-100) > 94 rand(-0.5) > 0.7692627344737486

นี่เพราะสำหรับ argument n ที่ส่งเข้า rand rand คืน random numbers จาก 0 ถึง (แต่ไม่รวม) n.to_i.abs สำหรับตัวอย่างข้างต้น (-100).to_i.abs คือ 100 และ (-0.5).to_i.abs คือ 0 ดังนั้น resulting random numbers

การเรียก rand(0) คล้ายกับการเรียก rand() คุณจะได้ random numbers ระหว่าง 0.0 และ 1.0 (ไม่ inclusive)

Generating Reproducible Sequences ด้วย Kernel#srand

ก่อนไป method ถัดไปของการ generate random numbers มาดู function srand ก่อน

Kernel#srand ตั้งค่า seed สำหรับ Kernel#rand เราสามารถใช้มัน generate repeatable sequences ของ random numbers ระหว่าง different runs ของโปรแกรม

เพื่อเข้าใจว่านี้หมายถึงอะไร เราต้องเข้าใจก่อนว่า random numbers ถูก generate อย่างไร

Generating "Random" Numbers จาก Seed

ตามที่กล่าวไว้ computers ไม่ generate truly random numbers เพียงจาก computation สิ่งที่ทำคือ generate sequence ของ numbers ที่ดูเหมือน random เพื่อทำนี้ computer เริ่มต้นด้วย seed number ซึ่งมัน run ผ่าน algorithm แล้วส่งออก seemingly random output

Seed number ถูก generate โดย computer ใช้ combination ของ different elements เช่น timestamp, process ID ของโปรแกรม ฯลฯ เพราะ elements เหล่านี้ vary สำหรับแต่ละ request ที่ generate random number seed number จะต่างกันเสมอ ซึ่งจะผลิต sequence ของ numbers ที่ต่างกัน ดังนั้น resulting random number output ถ้าคุณรัน algorithm ด้วย seed เดียวกัน คุณจะได้ sequence เดียวกันทุกครั้ง นี่คือสิ่งที่ Kernel#srand อนุญาตให้เราทำได้

srand มักใช้ใน testing อาจ handy สำหรับ test code ใน app ที่ deal กับ randomness ด้วย values ที่ random แต่ยัง predictable พอที่จะ test อาจช่วย isolate หรือ reproduce bugs

ด้านล่างเราใช้ srand ตั้ง seed แล้วเรียก rand ก่อนเพื่อผลิต individual random numbers สองตัว และจากนั้นผลิต sequences ของ random numbers สองชุด

srand(777) rand() > 0.152663734901322 rand() > 0.3023566097075212 10.times.map { rand(10) } > [7, 1, 7, 4, 7, 9, 8, 7, 2, 0] 10.times.map { rand(10) } > [1, 2, 4, 5, 7, 1, 7, 2, 2, 7]

ถ้าคุณรัน srand อีกครั้งด้วย seed เดียวกัน และทำ calls เดียวกับที่เราทำก่อนหน้านี้ คุณจะเห็นว่าเราได้ random numbers เดียวกัน

srand(777) rand() > 0.152663734901322 rand() > 0.3023566097075212 10.times.map { rand(10) } > [7, 1, 7, 4, 7, 9, 8, 7, 2, 0] 10.times.map { rand(10) } > [1, 2, 4, 5, 7, 1, 7, 2, 2, 7]

Generating Random Numbers ด้วย Random

คุณยังสามารถ generate random numbers ด้วย Random class

Class method rand ให้ base functionality ของ Kernel#rand พร้อม better handling ของ floating point values

Random.rand(1...10) > 5

ต่างจาก Kernel#rand ถ้า Random.rand ได้รับ negative หรือ 0 argument มันจะ raise ArgumentError

Generating Random Numbers ตาม Normal Distribution

ในโลกจริง หลายสิ่ง tend to follow Normal Distribution ถ้าคุณมี range ของ values ที่ something falls under นานาๆ คุณจะได้ equal distribution ของทุก values ไม่ได้ ส่วนใหญ่ majority ของ data tend to fall ภายใน smaller range ด้วย smaller percentage falling ภายใน larger range มาใช้ adult man's height เป็นตัวอย่าง Shortest height ที่ recorded คือ 54.6 cm (21.5 inches) ในขณะที่ tallest คือ 267 cm (8'9") ถ้าคุณอยาก generate data simulate height ของ men ใน population คุณอาจไม่อยากใช้ rand กับ limits เหล่านี้ คุณไม่อยากให้ probability ของการได้ 8'9" man เท่ากับ 6' man เพราะ latter common กว่า

ตัวอย่างอื่นของสิ่งที่ follow Normal Distribution:

  • Errors in measurements
  • Blood pressure
  • Test scores
  • Weight of an adult man/woman

เพื่อ generate better random numbers สำหรับ use cases เหล่านี้ คุณสามารถใช้ rubystats gem

$ gem install rubystats
require 'rubystats' adult_male_height = Rubystats::NormalDistribution.new(178, 10) sample = 50.times.map { adult_male_height.rng.round(1) } > [183.2, 169.5, 189.7, 171.9, 176.0, 179.3, 189.3, 175.3, 188.3, 190.0, 185.5, 182.8, 187.2, 191.6, 185.4, 178.4, 187.1, 183.3, 189.6, 179.7, 172.7, 174.4, 153.8, 197.4, 176.0, 174.6, 181.1, 182.0, 204.7, 185.2, 175.9, 167.7, 160.6, 170.5, 169.3, 160.6, 165.6, 166.4, 182.6, 179.7, 183.1, 171.9, 185.4, 175.4, 179.7, 176.9, 160.6, 173.8, 181.9, 190.2]

ในข้างต้น เราส่ง average height สำหรับชาย (178cm) และ standard deviation 10cm ให้ NormalDistribution.new ก่อน generate 50 values ที่ fall ใน normal distribution นี้ ถ้าสนใจ math บทความนี้อาจน่าสนใจคุณ

Random Roundup

นี่คือจุดจบของ discussion เรา cover 몇 가지 different ways ของการสร้าง 'random' numbers ใน Ruby ด้วย rand, srand, Random และ Rubystats เรายังสัมผัสพักๆ ว่า 'random' numbers ถูกสร้างอย่างไร และดูเหตุผลว่าทำไม deterministic devices ไม่สามารถสร้าง real random numbers ได้

คุณควรทราบว่า methods ที่ cover ไม่ได้ ideal สำหรับ all use cases ที่เรียก randomness Integer หรือ floating point numbers ที่ generate โดย methods อาจ ideal สำหรับ produce chance ใน gaming หรือ create simulations แต่ใน situations ที่เรียก security ตัวอย่างเมื่อ generate password reset token คุณควร consider ใช้ SecureRandom ด้วย SecureRandom คุณสามารถ generate hexadecimal, base64, binary และ UUID strings ที่ harder to crack มากกว่า plain numbers

หวังว่าคุณจะพบบางส่วนน่าสนใจ ถ้ามีความคิดเห็นหรือคำถามเกี่ยวกับสิ่งที่เรา cover โปรด reach out to us @AppSignal คุณยังสามารถส่ง requests สำหรับ topics ที่อยากให้ cover ได้

เรา update บทความนี้วันที่ August 1st, 2018 เพื่อรวม note เกี่ยวกับ SecureRandom