-
난수 동기화프로그래밍/기록, 개념, 용어 2018. 2. 6. 19:37반응형
컴퓨터에서 진정한 의미의 난수는 없다. 유사 난수 발생기가 동기화 불일치의 원인이 될 때가 있다. 게임에서 임의성은 필수적인 요소이므로 이것이 빠질 수도 없다.
클라이언트/서버 구조라면 서버에서 임의의 값을 지정함으로 동기화를 어떻게든 할 수 있다. 하지만 클라이언트 난수 시뮬레이션이 필요한 p2p에서라면?
c, 그리고 c++에서의 난수 발생
srand는 난수 발생기의 시드 값을 지정하고, rand는 난수를 생성한다.
srand로 특정 시드를 지정하고 나면 rand는 같은 순서로 일련의 숫자를 생성한다.
c 표준의 난수 발생기는(rand, srand) 어떤 난수 발생 알고리즘을 쓸지 명시되어있지 않다.
따라서 유저A의 PC와 유저 B의 PC는 같은 rand 호출에도 내부적으론 다른 알고리즘으로 돌아갈 여지가 있다.
문제는 이뿐만 아니다. rand는 게다가 전역적으로 호출될 수 있다.
같은 순서를 보장하기 위해선 같은 횟수가 호출되어야 한다. 게임 로직에서만 호출되어야 하는데 다른 라이브러리가 rand 함수를 호출해 순서가 깨질 수 있다는 것이다.
네트워크 게임에서 같은 난수를 도출하려면..
각 클라이언트의 난수 발생기에 같은 시드 값을 지정하고 같은 횟수로 난수 발생기를 호출하면 된다.
c++11부턴 난수 알고리즘이 표준으로 명시 되었으며, 이 중 메르센 트위스터 알고리즘은 널리 사용된다.
주의해라. 게임 상태용으로 쓰는 난수 발생기는 절대로 다른 곳에서 사용되면 안 된다.
이 때문에 전역적으로 사용되는 rand는 더더욱 부적합하다. 게임 로직에서는 호출되지 않으나 다른 라이브러리에서 호출되기라도 한다던가 할 여지가 크므로 위험도 크고 잡기도 어렵다.
메르센 트위스터
빠르고 좋은 난수 품질을 생성하는 유사 난수 생성기이다.
c++에서 이 알고리즘은 random에 std::mt19937로 명명되어있으며 19937은 2^19937-1 주기로 반복됨을 의미한다.
https://ko.wikipedia.org/wiki/%EB%A9%94%EB%A5%B4%EC%84%BC_%ED%8A%B8%EC%9C%84%EC%8A%A4%ED%84%B0
c++에서의 분포
c++에서 분포 클래스인 distribution 클래스 시리즈가 생성하는 값들은 컴파일러마다 다를 수 있다고 확인했다(2018-02-09 기준). 이는 구현 방식에 대한 가이드가 없어서 그런 것으로 보이며, 각 클라이언트가 랜덤에 대해 독자적인 시뮬레이션을 하는 경우, uniform_int_distribution 같은 것들을 사용하지 않고 자체적으로 쓸 분포 함수를 만들어야 할 것 같다.
https://wandbox.org/ 에서 컴파일러를 바꿔가며 테스트를 해봐도 확인할 수 있다. 컴파일러가 달라도 engine이 생성하는 임의 값들은 동일하나, distribution은 다르다.
#include <iostream>#include <algorithm>#include <random>using namespace std;int main(){random_device rd;mt19937 engine(0);uniform_int_distribution<int> dist(1, 6);for(int i = 0; i != 10; ++i){cout << dist(engine) << " ";}return 0;}반응형'프로그래밍 > 기록, 개념, 용어' 카테고리의 다른 글
verbose 모드 (0) 2018.12.08 poll api 이벤트들 (0) 2018.04.18 DNS와 DDNS (0) 2017.05.13 함수 호출 규약 vectorcall (0) 2016.04.17 컴포넌트 기반 설계 (0) 2016.04.05