2012-02-13 6 views
3

Ну, я действительно не знаю, как искать то, что я ищу. Google дает массу результатов, но не соответствует моим критериям.Случайный, но предсказуемый генератор чисел? [C++]

Итак, я спрашиваю его здесь: Есть ли какой-либо известный код, который может создать число, которое предсказуемо, выглядит случайным и основано на «семени» (в моем случае это временная метка unix) и между указанным диапазоном?

Я хочу, чтобы иметь возможность создавать прогноз погоды в скрипте для игры, в которой я кодирую (но мне нужен код C++, который я могу порт, я не думаю, что многие люди здесь знакомы с «PAWN» [ aka SMALL] скриптовый язык? :)). Идентификатор погоды варьируется от 0 до ~ 100, включая некоторые устаревшие идентификаторы (поэтому мое решение состояло в том, чтобы сделать массив с допустимыми идентификаторами погоды, поэтому нам не нужно беспокоиться об этих BAD_ID, давайте не будем делать эту функцию слишком сложной).

Я мог бы сделать такую ​​формулу, но проблема в прошлом была в том, что погода менялась слишком быстро (как и каждую секунду, хотя я где-то потерял код: /), и пока я действительно не в курсе идей о том, как я собираюсь сделать такую ​​формулу.

Любые предложения действительно оценены!

+0

Взгляните на [Boost.Random] (http://www.boost.org/libs/random/). – ildjarn

+1

Если ваша погода меняется слишком быстро, решение заключается не в том, чтобы получить «меньше» случайного генератора, а в том, чтобы выбирать другой шаблон реже. Это не помогает, если иды для «Солнца» и «Метели» находятся рядом друг с другом. –

+0

Есть ли какая-нибудь другая функция random(), которая не потребует от меня большого количества кода? (PHP, PAWN, C++ <- да, это толчок, но PAWN и PHP ... особенно PAWN) –

ответ

2

Посмотрите на реализацию C random number generator used by VB6. Он идеально подходит для игр, потому что он генерирует довольно правдоподобные случайные seqeuences, но использует семя, и одно и то же семя всегда генерирует одну и ту же последовательность. Поэтому в файлах данных игры вы можете сохранить набор начальных значений, которые дадут вам известные (но случайные) последовательности, которые вы можете легко воспроизвести.

Вот реализация, которая возвращает значения в диапазоне:

typedef int Int32; 
typedef unsigned int UInt32; 

class CRnd 
{ 
    private: 
     static const UInt32 INITIAL_VALUE = 0x50000; 
     static const UInt32 INCREMENT = 0xC39EC3; 
     static const UInt32 MULTIPLIER = 0x43FD43FD; 

    private: 
     UInt32 m_nRnd; 

    public: 
     CRnd() { m_nRnd = INITIAL_VALUE; }; 
     CRnd (IN UInt32 nSeed) { m_nRnd = nSeed; }; 
     virtual ~CRnd() {}; 

     Int32 Get (IN Int32 nFrom, IN Int32 nTo) 
     { 
      if (nTo < nFrom) // nFrom should be less than nTo 
      { 
       Int32 nTmp = nTo; 

       nTo = nFrom; 
       nFrom = nTmp; 
      } 
      else if (nTo == nFrom) 
      { 
       return (nTo); 
      } 

      m_nRnd = (m_nRnd * MULTIPLIER + INCREMENT) & 0xFFFFFF; 

      float fTmp = (float) m_nRnd/(float) 16777216.0; 

      return ((Int32) ((fTmp * (nTo - nFrom + 1)) + nFrom)); 
     }; 

     void SetSeed (IN UInt32 nSeed) { m_nRnd = nSeed; }; 
     UInt32 GetSeed() { return (m_nRnd); }; 
}; 
+0

Wow thanks, результаты действительно хорошие, просто взгляните: http://pastebin.com/WvgTSv7g Код: http://pastebin.com/D4KrXpgf –

+0

Добро пожаловать - надеюсь, что он будет хорошо работать для тебя. Мне всегда нравился этот простой алгоритм его воспроизводимости. С их помощью можно создавать огромные звездные системы, используя очень мало ввода. – xxbbcc

+0

Следует отметить, что это генератор случайных чисел ** очень плохой ** (статистические свойства этого объясняются ad nauseam на многих веб-сайтах). Кроме того, он использует совершенно нестандартный интерфейс, что затрудняет его использование с другими библиотеками. Его нельзя использовать в новом коде. –

2

Посмотрите на srand и rand для начала.

C++ 11 также включает в себя еще много продвинутых алгоритмов, но для удовлетворения основных потребностей достаточно двух.

Чтобы сохранить номера в диапазоне от 0 до n, используйте оператор %.

+0

К сожалению, srand() и rand() имеют тенденцию быть медленными в лучшем случае или плохого качества случайности во многих системах, которые могут возникать неожиданными способами, особенно если вы используете упорядоченные входы, как это предполагает этот вопрос. – Kaganar

+0

'rand' обычно достаточно хорош для игры. Конечно, это не очень хорошо, если вы статистик - он имеет тенденцию к рулону, умножению и добавлению, или что-то по этим линиям сложным. Скорее, я никогда не видел никаких причин жалобы; на каких платформах вы видели проблему? – StilesCrisis

+0

Сказать, что стандартный ранд обычно достаточно хорош для игры, является ложным понятием. В Linux, как правило, верно. В Windows, ударить и пропустить - у них есть некоторые довольно плохие реализации rand. У меня были проблемы с многоплатформенной игрой, которая имела странное поведение на одной платформе, но не другая из-за чрезмерно упрощенного ранда. А в графическом программировании он становится еще более преувеличенным. – Kaganar

2

Очевидно, что число не может быть «предсказуемым» и «случайным» - это противоречивые термины.

Я предполагаю, что вы имеете в виду это число, которое является как детерминированным и полурандомом.

К счастью для вас, это то, что генерируют генераторы псевдослучайных чисел (PRNG): когда они запускаются с последовательным семенем, они дают вам тот же результат.

Поэтому я бы рекомендовал установить ваше семя srandom, затем используя random() % MAX_VALUE, чтобы получить число от 0 до MAX_VALUE. Если вы получаете «плохую ценность», просто отправляйтесь снова. Повторяйте без повторного набора номера столько, сколько хотите.

1

Если вам требуется медленное изменение значения, вы можете использовать функцию шума, такую ​​как Perlin Noise.

0

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

В частности, вы хотите, чтобы целые числа хеш были целыми. Вы можете подобрать такую ​​функцию here. Я рекомендую один под названием «32-битный целостный хеш-функции Роберта Дженкинса» - всегда работал хорошо для меня.

Вы будете в конечном итоге с чем-то вроде:

int time_index = 3; 
int weather_state = integer_hash_function(time_index) % (MAX_VALUE - MIN_VALUE + 1) + MIN_VALUE 

Если вы хотите более интересное поведение погоды, вы можете линейно интерполировать между значениями времени.Вы можете использовать шум Perlin с линейными комбинациями такого интерполированного шума на разных частотах и ​​интенсивностях, чтобы сделать довольно приятное поведение. (Я сделал это с многопользовательскими RPG, и он хорошо работает.)

0

Проблема с srand и rand, что только их подписи вызовов (а не значения, которые они генерируют) продиктованы стандартом C. Если вам нужны переносные и детерминированные псевдослучайные числа, вы должны реализовать его самостоятельно. Вот класс, написанный на C++, который основан на одном, найденном в Numerical Recipes, и полностью переносится. Вы можете создать экземпляр случайного числа с семенем, если хотите. Я жестко программирую это семя вместо того, чтобы использовать время в случае, если я хочу повторять одну и ту же псевдослучайную последовательность. Вы также можете использовать метод RandomInteger(a,b) для получения целых чисел на полуоткрытом интервале [a, b).

class RandomNumberStream 
{ 
private: 
    unsigned long long u,v,w; 

public: 
    RandomNumberStream(int n=1); 
    double RandomDouble(); 
    double RandomDouble(double a, double b); 
    unsigned long long RandomInteger(); 
    unsigned long long RandomInteger(int a, int b); 
private: 
    unsigned long long int64(); 
} ; 



RandomNumberStream::RandomNumberStream(int n) 
{ 
    v = 4101842887655102017LL; 
    w = 1; 

    u = n^v; int64(); 
    v = u; int64(); 
    w = v; int64(); 
} 
double RandomNumberStream::RandomDouble() 
{ 
    return int64() * 5.42101086242752217E-20f; 
} 
double RandomNumberStream::RandomDouble(double a, double b) 
{ 
    return int64() * 5.42101086242752217E-20f * (b-a) + a; 
} 
unsigned long long RandomNumberStream::RandomInteger() 
{ 
    return int64(); 
} 
unsigned long long RandomNumberStream::RandomInteger(int a, int b) 
{ 
    return a + int64() % (b-a); 
} 
unsigned long long RandomNumberStream::int64() 
{ 
    u = u * 2862933555777941757LL + 7046029254386353087LL; 
    v ^= v>>17; v ^= v<<31; v ^= v>>8; 
    w = 4294957665U*(w & 0xffffffff) + (w>>32); 
    unsigned long long x = u^(u<<21); x ^= x>>35; x ^= x<<4; 
    return (x+v)^w; 
} 
0

Я думаю, вы можете использовать rand для генерации случайных чисел. Однако вы можете дать такое же значение srand, как сказать 99, чтобы ваши номера были случайными, но предсказуемыми каждый раз.

int iSecret = 0; 

/* initialize random seed: */ 
srand (99); 

/* generate secret number: */ 
iSecret = rand(); 
Смежные вопросы