2008-10-03 3 views
13

나는 각 숫자를 생성하기 전에 씨앗이 주어 졌을 때 빠르게 작동하는 의사 난수 생성기를 찾고 있습니다. 지금까지 본 대부분의 생성자는 시드를 한 번 설정 한 다음 긴 숫자 시퀀스를 생성한다고 가정합니다. 지금까지 필자가 보아 왔던 것과 비슷한 것은 Perlin Noise 뿐이지 만 유사한 "너무"부드러운 데이터를 생성합니다. 유사한 입력의 경우 유사한 결과를 생성하는 경향이 있습니다.절차적인 내용을위한 빠른 의사 난수 생성기

과 같이 보일 것입니다 발전기의 선언 :

int RandomNumber1(int seed); 

또는 :

int RandomNumber3(int seedX, int seedY, int seedZ); 

나는 그것의 입력을 해싱에 의해 RandomNumber3을 구현하기 위해 가능한 한 좋은 RandomNumber1이 충분해야한다 가진 생각을 결과를 RandomNumber1에 전달하지만 일부 구현에서는 독립적 인 입력을 사용할 수 있도록 2 차 프로토 타입을 작성했습니다.

이 생성기의 용도는 그리드에 나무를 놓고 숲을 생성하고 각 위치에 대해 임의의 나무 종과 임의의 공간 오프셋을 결정하는 등의 절차 콘텐츠 생성기에 사용하는 것입니다.

발생기는 렌더링 과정에서 절차 내용이 실시간으로 대량 생성되므로 매우 효율적이어야합니다 (500 CPU주기 미만).

+0

Perlin 노이즈가 비슷한 이유는 Perlin 노이즈가 결정적인 (반복 가능한) 의사 난수 함수를 사용하여 작업의 일부를 수행 한 다음 결과를 부드럽게 만드는 것입니다. Perlin 노이즈 구현, 특히 이전에 개선 된 초기 Perl 노이즈 구현을 보면 언어, 도메인 및 범위가 다양하지만 효율적이고 반복 가능한 "임의"함수 유형을 자주 찾을 수 있습니다. 예 : 'RandomNumber (vec2 seed, float x, float y) {return fract (sin (도트 (시드 + vec2 (fx, fy), vec2 (12.9898,78.233))) * 43758.5453); }'(GLSL ES) – LarsH

+0

나는이 질문을 연구하려고 노력해 왔으며, "발전기"라는 단어는 우리가 피하려고하는 순차적 인 스트리밍 동작을 의미한다는 결론에 도달했습니다. 이것이 PRN ** G **가 일반적으로 엄격한 결정 론적 기능이 아닌 상태 보존 기능을 제공하는 것으로 이해되는 이유입니다. 아마도 우리가 PRNG가 아닌 PRNF (기능)를 찾으면 연구에서 더 나은 성공을 거둘 수있을 것입니다. https://blogs.unity3d.com/2015/01/07/a-primer-on-repeatable-random-numbers/은 "임의의 해시 함수"라고합니다. – LarsH

답변

19

PRNG가 아닌 해시 함수를 요청하는 것처럼 보입니다. 인터넷 검색 '빠른 해시 함수'는 몇 가지 유망한 결과를 산출합니다.

For example

:

uint32_t hash(uint32_t a) 
    a = (a^61)^(a >> 16); 
    a = a + (a << 3); 
    a = a^(a >> 4); 
    a = a * 0x27d4eb2d; 
    a = a^(a >> 15); 
    return a; 
} 

편집 : 그래, 일부 해시 함수는 확실히 다른 사람보다 더 적합 보인다.

목적에 따라, 함수를 눈으로보고 입력의 단일 비트 변경이 많은 출력 비트로 전파되는지 확인하는 것으로 충분해야합니다.

+0

이것이 좋은 방향이라고 생각합니다. 처음에는 해시 함수가 하나의 중요한 속성 (균일 한 분포)을 가지고있는 것처럼 보였습니다. 출력이 "무작위"로 간주 될 수 있는지 확실하지 않습니다 - 특정 함수에 대해 출력이 얼마나 유사한지를 어떻게 알 수 있습니까? ? – Suma

+3

좋은 해시 함수에 대한 한 가지 테스트는 정수 0, 1, 2의 시퀀스를 제공하고 의사 난수 생성기 테스트를 사용하여 '임의성'에 대한 출력을 테스트하는 것입니다. – Aaron

+1

좋은 답변이지만, "PRNG가 아닌 해쉬 함수 *"에 동의하지 않습니다. 일반적으로 해시 함수는 항상 좋은 난수 생성기가 아닙니다 (다른 속성 (https://en.wikipedia.org/wiki/Hash_function#Properties)에 대해 더 많이 설계되었습니다). OP *는 특정 품질을 필요로합니다. 무작위성 또는 그의 숲이 가짜 보일 것입니다.즉, 일부 해시 함수는 "무작위 충분히"PRNG를 만들고, OP가 요구하는 것처럼 확실히 결정적입니다. – LarsH

9

그래, 당신은 PRNG가 아닌 빠른 정수 해시 알고리즘을 찾고 있습니다.

page에는 몇 가지 알고리즘이 있습니다. 정확한 검색 조건을 더 많이 알게 될 것입니다.

편집 : 원본 페이지가 삭제되었습니다. 라이브 버전은 found on GitHub 일 수 있습니다.

2

std::tr1::ranlux3 또는 표준 C++ 라이브러리에 TR1 추가의 일부인 다른 난수 생성기를 참조하십시오. 나는 초기에 mt19937을 제안했지만, 매우 빨라야한다는 메모를 보았습니다. TR1은 Microsoft VC++과 GCC에서 사용할 수 있어야하며 더 많은 컴파일러를 지원하는 부스트 라이브러리에서도 찾을 수 있습니다.boost documentation 각색

예 :

#include <random> 
#include <iostream> 
#include <iterator> 
#include <functional> 
#include <algorithm> 
#include <ctime> 
using namespace std; 
using namespace std::tr1; 
int main(){ 
    random_device trueRand; 
    ranlux3 rng(trueRand); // produces randomness out of thin air 
          // see pseudo-random number generators 
    uniform_int<> six(1,6); // distribution that maps to 1..6 
          // see random number distributions 
    variate_generator<ranlux3&, uniform_int<> > 
      die(rng, six); // glues randomness with mapping 

    // simulate rolling a die 
    generate_n(ostream_iterator<int>(cout, " "), 10, ref(die)); 
} 

예제 출력 :

2 4 4 2 4 5 4 3 6 2 

상관 TR1 난수 발생기는 다른 난수 생성기를 시드 할 수있다. 더 높은 품질의 결과가 필요하면 mt19937의 출력 (더 느리지 만 품질은 더 높음)을 더 빠른 생성기 인 minstd_rand 또는 randlux3에 공급하는 것이 좋습니다.

0

메모리가 실제로 문제가 아니며 속도가 가장 중요한 경우 난수 배열을 미리 작성하고 런타임시이를 반복 할 수 있습니다. 예를 들어이 같은 자신의 파일의 같은 별도의 프로그램을 10 만 난수를 생성 및 저장이

부호 INT randarray []

다음 해당 파일을에 포함 = {1,2,3, ...} 당신의 컴파일 할 때 런타임에 난수 함수는 해당 배열에서 숫자를 가져와야 만 끝까지 히트 할 때 다시 시작 지점으로 되돌아 가면됩니다.

+0

http://stackoverflow.com/questions/167735/#167764 에서처럼 간단한 해시를 계산하는 것은 거대한 배열 (거대한 배열은 캐시에 맞지 않으므로 액세스가 느리다)에 액세스하는 것보다 항상 빠릅니다. – Suma

+0

내 PC에서 프로파일 링하고 내 조회 테이블 방법과 해시 함수 비교를 사용하면 조회 테이블이 13 배 빨라집니다. – KPexEA

+0

룩업 테이블은 L2 캐시에 들어가기에 충분히 작고 L2 캐시를 사용하지 않는 경우 (테스트에서 가장 가능성이 높은) 더 빠를 수 있습니다. 실제 성능을 테스트하려면 조회간에 중요한 데이터 처리를 수행해야합니다. – Suma

5

다음은 George Marsaglia가 개발 한 작은 난수 생성기입니다. 그는 현장 전문가이기 때문에 발전기가 좋은 통계적 특성을 가지고 있음을 확신 할 수 있습니다.

v = 36969*(v & 65535) + (v >> 16); 
u = 18000*(u & 65535) + (u >> 16); 
return (v << 16) + u; 

여기에서 u와 v는 부호없는 int입니다. 0이 아닌 값으로 초기화하십시오. 난수를 생성 할 때마다 u와 v를 어딘가에 저장하십시오. 위의 서명과 일치하는 함수에서 이것을 감쌀 수 있습니다. (int는 부호가 없다는 것을 제외하고)

+0

불행히도 이것은이 질문과 일치하지 않습니다. 나는 내 자신의 U와 V를 매번 제공해야하며, 어딘가에 저장하고 반복 사이에서 업데이트하지 않아야한다. 이 함수는 동일한 입력이 주어지면 항상 동일한 출력을 생성해야합니다. – Suma

+0

@Suma :이 함수의 매개 변수로 전달할 때마다 매번 U와 V를 제공 할 수없는 이유는 무엇입니까? 그리고 매번 같은 U와 같은 V를 가짐으로써 항상 같은 결과를 얻을 수 있습니다. 귀하의 질문에 정확히 일치합니다! – Mecki

+0

나는 이것을 시도했지만 좋은 결과를 얻지 못했습니다. u를 1로 변화 시키더라도 출력이 크게 변경되지는 않습니다. – Aranda

0

자바 임의 번호 라이브러리에서 다음 코드를 사용합니다. 나는 또한 절차적인 내용을 생성하기 위해 이것을 사용한다.

/** 
* State for random number generation 
*/ 
private static volatile long state=xorShift64(System.nanoTime()|0xCAFEBABE); 

/** 
* Gets a long random value 
* @return Random long value based on static state 
*/ 
public static long nextLong() { 
    long a=state; 
    state = xorShift64(a); 
    return a; 
} 

/** 
* XORShift algorithm - credit to George Marsaglia! 
* @param a initial state 
* @return new state 
*/ 
public static final long xorShift64(long a) { 
    a ^= (a << 21); 
    a ^= (a >>> 35); 
    a ^= (a << 4); 
    return a; 
}