2009-04-15 3 views
2

Park-Miller-Carta PRNG 난수 생성기의 Java 구현을 만들려고합니다.Park Miller-Carta PRNG 임의 생성기 allways 2.33E-10을 반환합니다.

다음은 ActionScript 3의 랜덤 함수 구현입니다. from here. 이 항상 2.33E-10 반환

int seed = 20; //for example. 

public double random() { 
    seed = (seed * 16807) % 2147483647; 
    return seed/0x7FFFFFFF + 0.000000000233; 
} 

:

return (_currentSeed = (_currentSeed * 16807) % 2147483647)/0x7FFFFFFF 
                  + 0.000000000233; 

나는 자바에서 일이 점점 많은 행운을 가지고 있지 않다. 어떤 아이디어가 내가 자바에서 잘못하고있는 것인가? (AS3 코드는 0.0001565276181885122을 반환하고 20의 시드가있는 처음 두 응답은 0.6307557630963248).

+0

왜? 그것이 자신의 교화를위한 것이라면 그것은 한 가지입니다. 그러나 생산 코드가 실제로 (즉, 암호로 안전한) 난수 생성은 옳은 일을하기가 대단히 어렵습니다. RNG는 아마도 대부분의 암호 시스템에서 가장 큰 기술적 취약성 일 것입니다. –

+0

@Chris AND Park-Miller-Carta는 다소 나쁩니다. – Varkhan

답변

6
seed/0x7FFFFFFF 

는 정수 작업입니다. 정수 부분은 항상 "참"결과를 아래쪽으로 반올림합니다. 이 경우 결과는 0에서 1 사이이므로 연산은 항상 0을 반환합니다.

부동 소수점 결과를 얻으려면 적어도 하나의 인수가 float이어야하며 다음과 같이 수행 할 수 있습니다.

return (double)seed/0x7FFFFFFF + 0.000000000233; 
1

은 교체 :

return seed/0x7FFFFFFF+0.000000000233; 

로 : 두 인수가 정수이기 때문에

return (double)seed/0x7FFFFFFF+0.000000000233; 
1

운영자 우선 순위.

(seed/0x7FFFFFFF)+0.000000000233; 

입니다. 그게 당신이 의미 한 것입니까?

+0

AS3 코드가 그랬습니다.그래, 맞아. – Artelius

+1

아니요, 선행 규칙이 다를 수 있습니다. 또한 나누기 연산자의 의미가 다를 수 있습니다. 이는 발생한 것으로 보입니다. –

2

좋아요, 근본적인 문제는 다른 사람들이 지적했듯이 정수 나누기가 아닌 부동 소수점 나누기를해야한다는 것입니다.

그러나이 특정 코드를 수정하는 것은 요점과 관련이 있습니다. 왜 처음부터 신경 써야합니까? 그것은 본질적으로 같은 클래스의 알고리즘을 java.lang.Random으로 사용하고 있습니다!

빠른 생성기를 원할 경우 XORShift generator을 고려하십시오. 양질의 생성기를 원한다면, 당신은 SecureRandom을 가지고 있습니다. (훨씬 느리지 만) 숫자 작성법 알고리즘 (매우 빠른 결합 된 생성기)을 고려하면 다음과 같이 Java로 구현할 수 있습니다.

public class HighQualityRandom extends Random { 

    private Lock l = new ReentrantLock(); 
    private long u; 
    private long v = 4101842887655102017L; 
    private long w = 1; 

    public HighQualityRandom() { 
    this(System.nanoTime()); 
    } 
    public HighQualityRandom(long seed) { 
    l.lock(); 
    u = seed^v; 
    nextLong(); 
    v = u; 
    nextLong(); 
    w = v; 
    nextLong(); 
    l.unlock(); 
    } 

    @Override 
    public long nextLong() { 
    l.lock(); 
    try { 
     u = u * 2862933555777941757L + 7046029254386353087L; 
     v ^= v >>> 17; 
     v ^= v << 31; 
     v ^= v >>> 8; 
     w = 4294957665L * (w & 0xffffffff) + (w >>> 32); 
     long x = u^(u << 21); 
     x ^= x >>> 35; 
     x ^= x << 4; 
     return (x + v)^w; 
    } finally { 
     l.unlock(); 
    } 
    } 

    protected int next(int bits) { 
    return (int) (nextLong() >>> (64-bits)); 
    } 

} 

이 코드는 내가 필요한 코드에서 복사됩니다. 당신은 원칙적으로 자물쇠를 제거하거나, 그냥 정기적 인 동기화를 사용할 수 있습니다.

Park Miller-Carta 사용을 절대적으로 주장한다면, 난 적어도 임의의 서브 클래스로 포장하고, java.util.Random이 정수를 두 배로 변환하는 것을 처리하게한다. 객체 지향 언어의 확장 가능한 라이브러리는 ...