2009-04-15 2 views
2

Я пытаюсь выполнить реализацию Java генератора случайных чисел PRNG Park-Miller-Carta.Park-Miller-Carta Случайный генератор PRNG allways возвращает 2.33E-10

Ниже приведена реализация функции Random в ActionScript 3 from here.

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

Я не много удачи, получая эту работу в Java:

int seed = 20; //for example. 

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

Это всегда возвращает 2.33E-10. Любые идеи, что я делаю неправильно на Java? (код AS3 возвращает 0.0001565276181885122, затем 0.6307557630963248 для первых двух ответов с семенем 20).

+0

Почему? Если это для вашего собственного назидания, это одно, но для производственного кода действительно хорошее (т.е. криптографически безопасное) генерирование случайных чисел чрезвычайно сложно сделать правильно. RNG, вероятно, является самой большой технической уязвимостью в большинстве криптосистем. –

+0

@ Крис и Парк-Миллер-Карта довольно плохие. – Varkhan

ответ

6
seed/0x7FFFFFFF 

является операцией целым числом, так как оба аргумента являются целыми числами. Целочисленное деление всегда округляет «истинный» результат вниз. В этом случае истинный результат находится между 0 и 1, поэтому операция всегда возвращает 0.

Чтобы получить результат с плавающей запятой, по крайней мере один из аргументов должен быть поплавком, который может быть достигнут следующим образом:

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 из коробки (хотя он намного медленнее), рассмотрите алгоритм Numerical Recipes (довольно быстрый комбинированный генератор), который можно реализовать на 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, я бы по крайней мере обернул его в подклассу Random, и пусть java.util.Random позаботится о преобразовании ints в double и т. Д. В конце концов, вот что расширяемые библиотеки в объектно-ориентированном языке для ...

Смежные вопросы