Random
Random
Random은 Ruby의 의사 난수 생성기(PRNG, Pseudo-Random Number Generator)에 대한 인터페이스를 제공해요. PRNG가 만들어 내는 비트열은 결정적(deterministic)이지만, 실제 난수에 가깝게 동작해요. 이 비트열은 정수·부동소수점·이진 문자열 등으로 표현할 수 있어요.
출처: Ruby 4.0 API
본문
생성기는 Random.srand를 통해 시스템이 만들어 준 시드(seed)나 사용자가 지정한 시드 값으로 초기화할 수 있어요.
클래스 메서드 Random.rand는 Kernel.rand의 기본 기능에 더해 부동소수점 값을 더 잘 다루도록 개선된 버전이에요. 둘 다 Ruby 시스템 PRNG를 다루는 인터페이스죠.
Random.new는 Ruby 시스템 PRNG와는 독립적인 상태를 가진 새 PRNG를 만들어요. 그래서 서로 다른 시드 값이나 시퀀스 위치를 가진 여러 생성기를 동시에 둘 수 있어요. Random 객체는 marshaling이 가능하기 때문에, 시퀀스를 저장해 뒀다가 나중에 이어서 쓸 수도 있어요.
PRNG는 현재 기간(period)이 2**19937-1인 수정된 메르센 트위스터(Mersenne Twister)로 구현돼 있어요. 이 알고리즘은 암호학적 용도가 아니므로, 보안이 필요한 곳에서는 이 PRNG 대신 반드시 SecureRandom을 써야 해요.
다양한 형태의 난수 데이터를 만들 수 있는 편의 메서드를 추가해 주는 Random::Formatter 모듈도 함께 참고하세요.
Public Class Methods
bytes(size) → string
size 길이의 무작위 이진 문자열을 돌려줘요.
new(seed = Random.new_seed) → prng
seed로 초기 상태를 설정한 새 PRNG를 만들어요. seed를 생략하면 Random.new_seed로 생성기를 초기화해요. 시드 값 사용에 대한 자세한 내용은 Random.srand를 참고하세요.
new_seed → integer
임의의 시드 값을 돌려줘요. Random.new가 인자로 시드 값을 지정하지 않았을 때 이 값을 사용해요.
Random.new_seed #=> 115032730400174366788466674494640623225
rand → float / rand(max) → number / rand(range) → number
Ruby 시스템 PRNG를 사용해 난수를 돌려줘요. 관련 내용은 Random#rand도 함께 보세요.
seed → integer
Ruby 시스템 PRNG를 초기화할 때 쓰인 시드 값을 돌려줘요. 이 값을 나중에 다른 생성기를 초기화할 때 써서 같은 상태로 만들면, 같은 시퀀스의 숫자를 만들어 낼 수 있어요.
Random.seed #=> 1234
prng1 = Random.new(Random.seed)
prng1.seed #=> 1234
prng1.rand(100) #=> 47
Random.seed #=> 1234
Random.rand(100) #=> 47
srand(number = Random.new_seed) → old_seed
시스템 의사 난수 생성기를 number로 시딩(seed)해요. 이전 시드 값이 돌아와요. number를 생략하면 운영 체제가 제공하는 엔트로피 소스(Unix의 /dev/urandom이나 Windows의 RSA 암호화 제공자)로 생성기를 시딩하고, 여기에 시간·프로세스 ID·시퀀스 번호를 결합해요.
srand는 프로그램 실행 사이에 의사 난수 시퀀스를 재현 가능하게 만들 때 써요. 시드를 알려진 값으로 설정하면 테스트 시 프로그램을 결정적으로 만들 수 있죠.
srand 1234 # => 268519324636777531569100071560086917274
[ rand, rand ] # => [0.1915194503788923, 0.6221087710398319]
[ rand(10), rand(1000) ] # => [4, 664]
srand 1234 # => 1234
[ rand, rand ] # => [0.1915194503788923, 0.6221087710398319]
urandom(size) → string
플랫폼이 제공하는 기능을 사용해 문자열을 돌려줘요. 반환 값은 이진 형태의 암호학적으로 안전한 의사 난수일 것으로 기대돼요. 이 메서드는 플랫폼이 제공하는 기능이 결과를 준비하는 데 실패하면 RuntimeError를 발생시켜요.
2017년 기준 Linux 매뉴얼 페이지 random(7)에는 "오늘날 존재하는 어떤 암호 프리미티브도 256비트 이상의 보안을 약속할 수 없다"고 적혀 있어요. 그래서 이 메서드에 size > 32를 넘기는 것은 생각해 볼 문제가 될 수 있어요.
Random.urandom(8) #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"
Public Instance Methods
==(other) → true or false
두 생성기의 내부 상태가 같으면 true, 아니면 false를 돌려줘요. 동등한 생성기는 같은 의사 난수 시퀀스를 만들어 내요. 두 생성기가 같은 상태를 갖는 경우는 보통 같은 시드로 초기화됐을 때예요.
Random.new == Random.new # => false
Random.new(1234) == Random.new(1234) # => true
그리고 같은 호출 이력(invocation history)을 가져야 해요.
prng1 = Random.new(1234)
prng2 = Random.new(1234)
prng1 == prng2 # => true
prng1.rand # => 0.1915194503788923
prng1 == prng2 # => false
prng2.rand # => 0.1915194503788923
prng1 == prng2 # => true
bytes(size) → string
size 바이트를 담은 무작위 이진 문자열을 돌려줘요.
random_string = Random.new.bytes(10) # => "\xD7:R\xAB?_\x83\xCE\xFAkO"
random_string.size # => 10
rand(max) → number / rand(range) → number / rand → float
max가 Integer면 0 이상 max 미만의 무작위 정수를 돌려줘요. Kernel.rand와 달리 max가 음의 정수이거나 0이면 ArgumentError를 발생시켜요.
prng = Random.new
prng.rand(100) # => 42
max가 Float면 0.0 이상이고 max 미만인 무작위 부동소수점을 돌려줘요. Kernel.rand와는 다르게 동작한다는 점에 주의하세요.
prng.rand(1.5) # => 1.4600282860034115
rand(1.5) # => 0
range가 Range면 range.member?(number) == true가 되는 난수를 돌려줘요.
prng.rand(5..9) # => one of [5, 6, 7, 8, 9]
prng.rand(5...9) # => one of [5, 6, 7, 8]
prng.rand(5.0..9.0) # => between 5.0 and 9.0, including 9.0
prng.rand(5.0...9.0) # => between 5.0 and 9.0, excluding 9.0
범위의 시작과 끝 값은 모두 뺄셈(-)과 덧셈(+) 메서드에 응답해야 해요. 그렇지 않으면 rand가 ArgumentError를 발생시켜요.
seed → integer
생성기를 초기화할 때 쓰인 시드 값을 돌려줘요. 이 값을 나중에 다른 생성기의 초기화에 사용해 같은 상태로 만들면 같은 시퀀스의 숫자를 만들어 낼 수 있어요.
prng1 = Random.new(1234)
prng1.seed #=> 1234
prng1.rand(100) #=> 47
prng2 = Random.new(prng1.seed)
prng2.rand(100) #=> 47