Random numbers hữu ích cho nhiều mục đích như gaming, encryption, building simulations. Về mặt kỹ thuật, computer không thể generate truly random numbers thuần túy bằng computation. Vô lý sinh ra truly random numbers trên deterministic device. Tốt nhất chỉ pseudorandom numbers - stream numbers xuất hiện như generated randomly.
Bài này xem các cách generate random numbers trong Ruby.
Generating Random Numbers với Kernel#rand
Bắt đầu, generate random numbers với method rand. Gọi method không argument, trả float >= 0.0 và < 1.0.
rand() # > 0.7308136972953823
Để lấy integer, pass integer cho function. Function trả random integer >= 0 và < integer pass. Mỗi lần chạy sau, bạn get số giữa 0 và 7.
rand(8) # > 5
Random number trong range cụ thể, pass Range cho rand.
Sau dùng inclusive Range generate random từ lower limit (1) đến (và include) upper limit (10).
rand(1..10) # > 6
Ví dụ sau dùng non-inclusive Range generate từ lower limit đến (nhưng không include) upper limit.
rand(1...10) # > 9
Range cũng có thể giữa floating point values.
rand(1.5..3.0) # > 1.7494305393711571
Cũng dùng negative range limits với rand.
rand(-5..-1) # > -5
Pass single negative numbers có thể cho surprising results, như dưới.
rand(-100) # > 94
rand(-0.5) # > 0.7692627344737486
Đây là vì argument n pass vào rand, rand trả random từ 0 đến (không include) n.to_i.abs. Ví dụ (-100).to_i.abs là 100 và (-0.5).to_i.abs là 0, do đó random numbers kết quả.
Gọi rand(0) tương tự rand(). Random numbers giữa 0.0 và 1.0 (không inclusive).
Generating Reproducible Sequences với Kernel#srand
Trước khi sang method tiếp theo, xem srand function.
Kernel#srand set seed cho Kernel#rand. Dùng để generate repeatable sequences random numbers giữa different runs của program.
Để hiểu ý nghĩa, trước hiểu random numbers generate như thế nào.
Generating "Random" Numbers từ Seed
Như nói trước, computer không generate truly random numbers từ computation. Chúng generate sequence numbers似乎 random. Để làm này, computer start với seed number, run qua algorithm và spit out seemingly random output.
Seed number generated bởi computer dùng combination các element khác nhau, ví dụ timestamp, process ID của program, etc. Vì các element này vary cho mỗi request generate random number, seed number luôn khác, produce different sequence numbers, thus random number output. Nếu run algorithm với same seed, bạn get same sequence numbers mỗi lần. Đây là điều Kernel#srand cho phép.
srand thường dùng trong testing. Handy cho test code deal với randomness, với values random nhưng vẫn predictable đủ test. Cũng giúp isolate hoặc reproduce bugs.
Dưới dùng srand set seed rồi gọi rand đầu produce vài individual random numbers rồi vài 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]
Nếu run srand lại với same seed và make same calls trước, bạn thấy same 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 với Random
Cũng generate random numbers với class Random.
Class method rand cung cấp base functionality của Kernel#rand cùng better handling floating point values.
Random.rand(1...10) # > 5
Khác Kernel#rand, nếu Random.rand given negative hoặc 0 argument, raise ArgumentError.
Generating Random Numbers Based on Normal Distribution
Trong real world, nhiều things tend to follow Normal Distribution. Nếu có range values something falls under, hiếm khi get equal distribution tất cả values. Phần lớn data tend to fall trong smaller range, phần trăm nhỏ fall trong larger range. Ví dụ adult man's height. Shortest recorded 54.6cm (21.5 inches) tallest 267cm (8'9"). Nếu generate data simulate height men trong population, có thể không muốn dùng rand với limits này. Không muốn probability get 8'9" man bằng get 6' man, vì sau common hơn.
Ví dụ khác follow Normal Distribution:
- Errors in measurements
- Blood pressure
- Test scores
- Weight of adult man/woman
Để generate better random numbers cho use cases này, dùng gem rubystats.
$ 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]
Ở trên, pass average height men (178cm) và standard deviation 10cm cho NormalDistribution.new, trước khi generate 50 values fall trong normal distribution này. Nếu tò mò math, bài này có thể interest bạn.
Random Roundup
Đến cuối discussion. Cover vài cách tạo 'random' numbers trong Ruby, với rand, srand, Random và Rubystats. Cũng briefly touch cách 'random' numbers tạo và lý do deterministic devices không tạo real random numbers.
Lưu ý methods cover không ideal cho all use cases gọi randomness. Integer/float numbers generated có thể ideal cho chance gaming hoặc simulations, nhưng situations gọi security, ví dụ generate password reset token, nên consider dùng SecureRandom. Với SecureRandom, generate hexadecimal, base64, binary và UUID strings harder to crack so với plain numbers.
Hy vọng bạn thấy thú vị. Comment hoặc question về cover, reach out @AppSignal. Cũng gửi requests topic muốn cover.
Updated article August 1st, 2018 include note on SecureRandom