Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

가중 난수를 생성하는 방법

난수는 일반적으로 우리가 '균일 분포'라고 부르는 것을 따릅니다. 즉, 임의의 숫자가 선택될 확률이 동일합니다.

그러나 일부 숫자를 다른 숫자보다 더 자주 선택하려면 가중 난수 생성기와 같은 다른 전략이 필요합니다. .

몇 가지 실용적인 응용 프로그램은 다음과 같습니다.

  • 비디오 게임의 전리품 테이블에서 적들이 다양한 드롭률로 다양한 아이템을 드롭할 수 있습니다.
  • 더 많은 티켓을 소지한 사람이 더 많은 당첨 기회를 얻을 수 있는 복권

간단한 전략

추첨 예에 대해 생각해 보면 분명한 해결책을 생각해 낼 수 있습니다. 각 '티켓'에 대해 항목 사본이 하나씩 있는 배열을 생성하는 것입니다.

예를 들어 John이 4개의 복권 티켓을 구매하고 David가 1개만 구매하는 경우 John은 David보다 4배 더 많은 당첨 기회를 갖게 됩니다.

실제 구현은 다음과 같습니다. :

users  = { john: 4, david: 1 }
raffle = []

users.map do |name, tickets|
  tickets.times { raffle << name }
end

p raffle
# [:john, :john, :john, :john, :david]

p raffle.sample
# :john

나는 그들이 구입한 모든 티켓에 대해 그 사람의 이름을 한 번씩 추가하고 그 목록에서 임의의 이름을 선택합니다. 목록에 더 많이 오르는 덕분에 그 이름이 선택될 확률이 높아집니다.

나는 이 접근 방식이 매우 간단하고 목록이 있으면 매우 빠르게 승자를 선택할 수 있기 때문에 이 방식을 좋아합니다.

가중치의 합

메모리를 더 효율적으로 사용할 수 있는 또 다른 방법이 있는데, 무작위 값을 선택하는 것이 더 느리다는 단점이 있습니다.

아이디어는 1과 모든 가중치의 합 사이에서 임의의 숫자를 선택한 다음 이 숫자보다 작거나 같은 가중치를 찾을 때까지 반복하는 것입니다.

코드는 다음과 같습니다. :

def random_weighted(weighted)
  max    = sum_of_weights(weighted)
  target = rand(1..max)

  weighted.each do |item, weight|
    return item if target <= weight
    target -= weight
  end
end

def sum_of_weights(weighted)
  weighted.inject(0) { |sum, (item, weight)| sum + weight }
end

이 코드는 키가 항목이고 값이 가중치인 해시를 사용합니다. 다음과 같이 이 메서드를 호출할 수 있습니다.

random_weighted(cats: 5, dogs: 1)
# :cats

여러 번 실행한 후 결과 분포를 보면 예상대로 작동하는지 테스트할 수 있습니다.

예시입니다 :

counts = Hash.new(0)

def pick_number
  random_weighted(cats: 2, dogs: 1)
end

1000.times { counts[pick_number] += 1 }
p counts

이것을 몇 번 실행하고 출력을 보고 비율이 올바른지 확인하십시오.

결론

더 정교한 알고리즘이 있지만 이 두 가지가 잘 작동합니다. 이 기사가 도움이 되었기를 바랍니다. 계속해서 더 많은 글을 쓸 수 있도록 친구들과 공유해 주세요!