2014-12-22 4 views
0

동일한 입력 집합이 주어지면 동일한 출력을 생성하는 C#에서 의사 난수 생성기를 만들려고합니다. 그것은 빠르며, 64 비트 숫자를 받아들이며, 특히 중요한 것은 임의의 입력을 허용해야합니다. 출력은 [0과 1 사이의] 이중이어야합니다.다중 64 비트 입력의 결정 성 랜덤 잡음 생성기?

대부분 입력 값은 앱의 수명 기간 동안 일정하게 유지되는 시드 값이며 x, y, z 및 w 좌표와 같은 하나 이상의 다른 숫자 값이 될 수 있습니다. int32, int64 또는 double 유형

나는 내가 발견 한 다른 난수 생성기를 적용하려고 시도했으나 주제를 둘러싼 이론이나 소수의 수학적 속성에 대해 전혀 몰랐기 때문에 응집에 큰 문제가 계속 발생했다. , 대부분의 경우에 역할을하는 것으로 보인다.

필자는 자체 알고리즘과 Perlin 노이즈와 같은 표준 알고리즘을 비롯한 여러 알고리즘에서 내부적으로 사용될 임의 노이즈를 생성하는 데이 함수를 사용하려고합니다.

어떻게해야합니까?

+1

"특히 중요한 것은 임의의 입력 집합을 허용합니다." - 어떤 값을 해시하고 해당 해시를 시드로 사용할 수 있습니다. –

+0

저는 같은 결론을 내 렸습니다. 즉, 입력의 바이트 배열을 구성하고 해시를 생성했습니다. –

+0

바이트 배열에서 해시를 생성하는 경우 음수 0과 부동 소수점 정확도에주의해야 할 수 있습니다. –

답변

1

이 약 10 배 빠른 속도를 기반으로 Murmur3에 비해 여전히 매우 느린 RNG이지만. 생성 된 모든 숫자에 대해 재사용 할 때 비용이 발생하므로 결과에 비 체계적인 영향을 미치는 많은 수의 시드가 필요합니다.

업데이트 : 약한 비트를 허용 할 이유가 없습니다.이 버전에는 명백한 패턴이 없어야합니다.

class Prng 
{ 
    const double shift3 = .125; 
    const double shift9 = shift3 * shift3 * shift3; 
    const double shift27 = shift9 * shift9 * shift9; 
    const double shift53 = shift27 * shift27 * 2.0; 
    public ulong rndlong(ulong a, ulong b, ulong c, ulong d){ 
     ulong e = ((a^(b >> 14 | b << 50)) + ((c >> 31 | c << 33)^(d >> 18 | d << 46)))*1911413418482053185; 
     ulong f = (((a >> 30 | a << 34)^c) + ((b >> 32 | b << 32)^(d >> 50 | d << 14)))*1139072524405308145; 
     ulong g = (((a >> 49 | a << 15)^(d >> 33 | d << 31)) + (b^(c >> 48 | c << 16)))*8792993707439626365; 
     ulong h = (((a >> 17 | a << 47)^(b >> 47 | b << 17)) + ((c >> 15 | c << 49)^d))*1089642907432013597; 
     return (e^f^(g >> 21 | g << 43)^(h >> 44 | h << 20)) * 2550117894111961111 + 
      ((e >> 20 | e << 44)^(f >> 41 | f << 23)^(g >> 42 | g << 22)^h) * 8786584852613159497 + 
      ((e >> 43 | e << 21)^(f >> 22 | f << 42)^g^(h >> 23 | h << 41)) * 3971056679291618767; 
    } 
    public double rnddouble(ulong a, ulong b, ulong c, ulong d) 
    { 
     return (double)(rndlong(a, b, c, d) >> 11) * shift53; 
    } 
} 
+0

첫 번째 매개 변수로 시드를 사용하고 필요없는 매개 변수를 0으로 가정합니다. 어떻게 비트 시프트를 사용할지 결정 했습니까? 다섯 번째 매개 변수를 원한다면 수정해야하기 때문에 물어 봅니다. 이 경우 당신은 무엇을 제안합니까? –

+0

모든 비트의 입력이 출력의 모든 비트에 잠재적으로 영향을 미치는지 확인하려고했습니다. 큰 수의 곱셈은 비트를 위쪽으로 퍼 뜨리므로 첫 번째 비트 시프트로 모든 비트의 비트가 비트 쉬프트 값의 합리적으로 낮은 비트에서 발생하는지 확인한 다음 첫 번째 곱셈 이후 모든 입력 비트의 영향이 확산됩니다 적어도 중간 변수 중 하나 이상에 대해, 그리고 나서 나는 기본적으로 동일한 것을 다시 수행하여 나머지 간격을 채 웁니다. – aaaaaaaaaaaa

+1

더 긴 버전을 얻는 가장 쉬운 방법은'rnddouble (rndlong (in1, in2, in3, in4), in5, in6, in7)의 4 입력 버전을 데이지 체인 방식으로 연결하는 것입니다. ' – aaaaaaaaaaaa

0

누군가 내가 왜 안되는지 확신 할 때까지 사용할 솔루션을 찾았습니다.

아래 코드는 내 수업에서 사용할 수있는 발췌문입니다. 첫 번째 Generate 함수는 필요에 따라 여러 가지 오버로드를 취할 수 있습니다. 입력을 바이트 배열로 변환하고 나머지를 수행하는 개인의 Generate 메소드로 전달합니다. 내부적으로는 _seed에 대한 참조가 있습니다. 이는 단지 바이트 배열 자체이며 생성자를 통해 제공하는 시드 값에서 생성됩니다.

또한 코드는 this MurMurHash3 algorithm에 종속되므로 매우 빠릅니다.

배포를 확인하기 위해 많은 수의 반복 작업을 실행했으며 매우 균일하게 분포되어 있으며, 주어진 값 주위에 사람이 눈에 띄지 않는 덩어리가 없습니다. 필자는 인텔 코어 i7에서 약 720ms에 백만 개의 값을 생성하고 있는데, 이는 내 용도에 충분히 빠르다. 또한 텍스쳐에서 2D 화이트 노이즈를 생성 해내는 테스트를 거쳤으며 노이즈는 무작위로 보입니다.

public double Generate(double x, double y, double z, double w) 
{ 
    return Generate(
     _seed, 
     BitConverter.GetBytes(x), 
     BitConverter.GetBytes(y), 
     BitConverter.GetBytes(z), 
     BitConverter.GetBytes(w) 
    ); 
} 

private double Generate(params byte[][] inputs) 
{ 
    var len = 0; 
    int i; 
    for(i = 0; i < inputs.Length; i++) 
     len += inputs[i].Length; 
    var buffer = new byte[len]; 
    var offset = 0; 
    for(i = 0; i < inputs.Length; i++) 
    { 
     var bytes = inputs[i]; 
     Buffer.BlockCopy(bytes, 0, buffer, offset, bytes.Length); 
     offset += bytes.Length; 
    } 
    return Hash(buffer); 
} 

private double Hash(byte[] bytes) 
{ 
    var hash = new Murmur3().ComputeHash(bytes); 
    var buffer = new byte[8]; 
    for(var i = 0; i < hash.Length; i++) 
     buffer[i%8] ^= hash[i]; 
    var n = BitConverter.ToInt64(buffer, 0); 
    if(n < 0) n = -n; 
    if(n == long.MaxValue) n--; 
    return n/(double)long.MaxValue; 
} 
+0

초당 백만 값이 약간 느립니다. 또한'-long.MinValue'가'long.MinValue'로 오버 플로우된다는 것을 기억하십시오. 결과를 양수 부호있는 정수로 캡핑하고 싶다면'n = n & long.MaxValue'를 사용할 수 있습니다. – aaaaaaaaaaaa

+0

@eBusiness 주셔서 감사합니다. 그에 따라 모드 코드를 수정하겠습니다. 속도에 대한 귀하의 의견을 감안할 때, 내가 대신해야한다고 제안합니까? –

+0

Murmur를 없애라. 데이터 블록이 큰 경우에는 빠르지 만 초기 초기화에는 여전히 많은 돈을 지불하고있다. 또한, 당신이 정말로 무엇을하고 있는지를 알지 못한다면, 어떻게 float을 입력으로 사용할 수 있다고 생각하는지 확신 할 수 없습니다. 결정론을 원한다면, 수레에서 멀리 떨어져 있어야합니다. 비싼 물건에 의존하지 않는 것을 요리 할 수있을 것 같아요. – aaaaaaaaaaaa