2013-02-08 2 views
5

Мне нужен генератор случайных чисел, который производит такую ​​же последовательность чисел как в iOS, так и в Android, если мы дадим одно и то же Семя в обоих.Генератор случайных чисел для iOS и Android

Я попробовал функцию rand() с помощью srand (1000). Но он дал разные результаты. Тогда я попробовал mersenne twister. Но это тоже дало разностную последовательность для того же семени.

Может ли кто-нибудь помочь мне в этом.

Я использую cocos2d-x для своего развития.

+0

хмм я бы подумал Вихрь Мерсенна должен дать тот же результат, используя те же семена. –

+0

: - (... Нет. Я проверил. – Aaron

+3

Я не хочу звучать придирчиво, но в эти дни я бы не назвал это генератором случайных чисел, если он полностью предсказуем на разных устройствах. Это псевдослучайное число генератор в лучшем случае ... Надеюсь, что это не для _security _... –

ответ

2

Я приспособил онлайн библиотеку CRandomMersenne, и я очень сожалею, что не могу больше найти источник для того. Но вот моя реализация Вихрь Мерсенна:

// Define 32 bit signed and unsigned integers. 
// Change these definitions, if necessary, to match a particular platform 
#if defined(_WIN16) || defined(__MSDOS__) || defined(_MSDOS) 
    // 16 bit systems use long int for 32 bit integer 
    typedef long int   int32; // 32 bit signed integer 
    typedef unsigned long int uint32; // 32 bit unsigned integer 
#else 
    // Most other systems use int for 32 bit integer 
    typedef int    int32; // 32 bit signed integer 
    typedef unsigned int  uint32; // 32 bit unsigned integer 
#endif 

// Define 64 bit signed and unsigned integers, if possible 
#if (defined(__WINDOWS__) || defined(_WIN32)) && (defined(_MSC_VER) || defined(__INTEL_COMPILER)) 
    // Microsoft and other compilers under Windows use __int64 
    typedef __int64   int64; // 64 bit signed integer 
    typedef unsigned __int64 uint64; // 64 bit unsigned integer 
    #define INT64_DEFINED    // Remember that int64 is defined 
#elif defined(__unix__) && (defined(_M_IX86) || defined(_M_X64)) 
    // Gnu and other compilers under Linux etc. use long long 
    typedef long long   int64; // 64 bit signed integer 
    typedef unsigned long long uint64; // 64 bit unsigned integer 
    #define INT64_DEFINED    // Remember that int64 is defined 
#else 
    // 64 bit integers not defined 
    // You may include definitions for other platforms here 
#endif 

void EndOfProgram(void);    // System-specific exit code (userintf.cpp) 

void FatalError(char * ErrorText);  // System-specific error reporting (userintf.cpp) 

class CRandomMersenne {    // Encapsulate random number generator 
#if 0 
    // Define constants for type MT11213A: 
#define MERS_N 351 
#define MERS_M 175 
#define MERS_R 19 
#define MERS_U 11 
#define MERS_S 7 
#define MERS_T 15 
#define MERS_L 17 
#define MERS_A 0xE4BD75F5 
#define MERS_B 0x655E5280 
#define MERS_C 0xFFD58000 
#else  
    // or constants for type MT19937: 
#define MERS_N 624 
#define MERS_M 397 
#define MERS_R 31 
#define MERS_U 11 
#define MERS_S 7 
#define MERS_T 15 
#define MERS_L 18 
#define MERS_A 0x9908B0DF 
#define MERS_B 0x9D2C5680 
#define MERS_C 0xEFC60000 
#endif 
public: 
    CRandomMersenne(uint32 seed) {  // Constructor 
     RandomInit(seed); LastInterval = 0;} 
    void RandomInit(uint32 seed);  // Re-seed 
    void RandomInitByArray(uint32 seeds[], int length); // Seed by more than 32 bits 
    int IRandom (int min, int max);  // Output random integer 
    int IRandomX(int min, int max);  // Output random integer, exact 
    double Random();     // Output random float 
    uint32 BRandom();     // Output random bits 
private: 
    void Init0(uint32 seed);   // Basic initialization procedure 
    uint32 mt[MERS_N];     // State vector 
    int mti;       // Index into mt 
    uint32 LastInterval;    // Last interval length for IRandomX 
    uint32 RLimit;      // Rejection limit used by IRandomX 
    enum TArch {LITTLE_ENDIAN1, BIG_ENDIAN1, NONIEEE}; // Definition of architecture 
    TArch Architecture;     // Conversion to float depends on architecture 
};  


class CRandomMother {    // Encapsulate random number generator 
public: 
    void RandomInit(uint32 seed);  // Initialization 
    int IRandom(int min, int max);  // Get integer random number in desired interval 
    double Random();     // Get floating point random number 
    uint32 BRandom();     // Output random bits 
    CRandomMother(uint32 seed) { // Constructor 
     RandomInit(seed);} 
protected: 
    uint32 x[5];      // History buffer 
}; 

#endif 

void CRandomMersenne::Init0(uint32 seed) { 
    // Detect computer architecture 
    union {double f; uint32 i[2];} convert; 
    convert.f = 1.0; 
    if (convert.i[1] == 0x3FF00000) Architecture = LITTLE_ENDIAN1; 
    else if (convert.i[0] == 0x3FF00000) Architecture = BIG_ENDIAN1; 
    else Architecture = NONIEEE; 

    // Seed generator 
    mt[0]= seed; 
    for (mti=1; mti < MERS_N; mti++) { 
     mt[mti] = (1812433253UL * (mt[mti-1]^(mt[mti-1] >> 30)) + mti); 
    } 
} 

void CRandomMersenne::RandomInit(uint32 seed) { 
    // Initialize and seed 
    Init0(seed); 

    // Randomize some more 
    for (int i = 0; i < 37; i++) BRandom(); 
} 


void CRandomMersenne::RandomInitByArray(uint32 seeds[], int length) { 
    // Seed by more than 32 bits 
    int i, j, k; 

    // Initialize 
    Init0(19650218); 

    if (length <= 0) return; 

    // Randomize mt[] using whole seeds[] array 
    i = 1; j = 0; 
    k = (MERS_N > length ? MERS_N : length); 
    for (; k; k--) { 
     mt[i] = (mt[i]^((mt[i-1]^(mt[i-1] >> 30)) * 1664525UL)) + seeds[j] + j; 
     i++; j++; 
     if (i >= MERS_N) {mt[0] = mt[MERS_N-1]; i=1;} 
     if (j >= length) j=0;} 
    for (k = MERS_N-1; k; k--) { 
     mt[i] = (mt[i]^((mt[i-1]^(mt[i-1] >> 30)) * 1566083941UL)) - i; 
     if (++i >= MERS_N) {mt[0] = mt[MERS_N-1]; i=1;}} 
    mt[0] = 0x80000000UL; // MSB is 1; assuring non-zero initial array 

    // Randomize some more 
    mti = 0; 
    for (int i = 0; i <= MERS_N; i++) BRandom(); 
} 


uint32 CRandomMersenne::BRandom() { 
    // Generate 32 random bits 
    uint32 y; 

    if (mti >= MERS_N) { 
     // Generate MERS_N words at one time 
     const uint32 LOWER_MASK = (1LU << MERS_R) - 1;  // Lower MERS_R bits 
     const uint32 UPPER_MASK = 0xFFFFFFFF << MERS_R;  // Upper (32 - MERS_R) bits 
     static const uint32 mag01[2] = {0, MERS_A}; 

     int kk; 
     for (kk=0; kk < MERS_N-MERS_M; kk++) {  
     y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); 
     mt[kk] = mt[kk+MERS_M]^(y >> 1)^mag01[y & 1];} 

     for (; kk < MERS_N-1; kk++) {  
     y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK); 
     mt[kk] = mt[kk+(MERS_M-MERS_N)]^(y >> 1)^mag01[y & 1];}  

     y = (mt[MERS_N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK); 
     mt[MERS_N-1] = mt[MERS_M-1]^(y >> 1)^mag01[y & 1]; 
     mti = 0; 
    } 

    y = mt[mti++]; 

#if 1 
    // Tempering (May be omitted): 
    y ^= y >> MERS_U; 
    y ^= (y << MERS_S) & MERS_B; 
    y ^= (y << MERS_T) & MERS_C; 
    y ^= y >> MERS_L; 
#endif 

    return y; 
} 


double CRandomMersenne::Random() { 
    // Output random float number in the interval 0 <= x < 1 
    union {double f; uint32 i[2];} convert; 
    uint32 r = BRandom();    // Get 32 random bits 
    // The fastest way to convert random bits to floating point is as follows: 
    // Set the binary exponent of a floating point number to 1+bias and set 
    // the mantissa to random bits. This will give a random number in the 
    // interval [1,2). Then subtract 1.0 to get a random number in the interval 
    // [0,1). This procedure requires that we know how floating point numbers 
    // are stored. The storing method is tested in function RandomInit and saved 
    // in the variable Architecture. 

    // This shortcut allows the compiler to optimize away the following switch 
    // statement for the most common architectures: 
#if defined(_M_IX86) || defined(_M_X64) || defined(__LITTLE_ENDIAN__) 
    Architecture = LITTLE_ENDIAN1; 
#elif defined(__BIG_ENDIAN__) 
    Architecture = BIG_ENDIAN1; 
#endif 

    switch (Architecture) { 
    case LITTLE_ENDIAN1: 
     convert.i[0] = r << 20; 
     convert.i[1] = (r >> 12) | 0x3FF00000; 
     return convert.f - 1.0; 
    case BIG_ENDIAN1: 
     convert.i[1] = r << 20; 
     convert.i[0] = (r >> 12) | 0x3FF00000; 
     return convert.f - 1.0; 
    case NONIEEE: default: ; 
    } 
    // This somewhat slower method works for all architectures, including 
    // non-IEEE floating point representation: 
    return (double)r * (1./((double)(uint32)(-1L)+1.)); 
} 


int CRandomMersenne::IRandom(int min, int max) { 
    // Output random integer in the interval min <= x <= max 
    // Relative error on frequencies < 2^-32 
    if (max <= min) { 
     if (max == min) return min; else return 0x80000000; 
    } 
    // Multiply interval with random and truncate 
    int r = int((max - min + 1) * Random()) + min; 
    if (r > max) r = max; 
    return r; 
} 


int CRandomMersenne::IRandomX(int min, int max) { 
    // Output random integer in the interval min <= x <= max 
    // Each output value has exactly the same probability. 
    // This is obtained by rejecting certain bit values so that the number 
    // of possible bit values is divisible by the interval length 
    if (max <= min) { 
     if (max == min) return min; else return 0x80000000; 
    } 
#ifdef INT64_DEFINED 
    // 64 bit integers available. Use multiply and shift method 
    uint32 interval;     // Length of interval 
    uint64 longran;      // Random bits * interval 
    uint32 iran;      // Longran/2^32 
    uint32 remainder;     // Longran % 2^32 

    interval = uint32(max - min + 1); 
    if (interval != LastInterval) { 
     // Interval length has changed. Must calculate rejection limit 
     // Reject when remainder = 2^32/interval * interval 
     // RLimit will be 0 if interval is a power of 2. No rejection then 
     RLimit = uint32(((uint64)1 << 32)/interval) * interval - 1; 
     LastInterval = interval; 
    } 
    do { // Rejection loop 
     longran = (uint64)BRandom() * interval; 
     iran = (uint32)(longran >> 32); 
     remainder = (uint32)longran; 
    } while (remainder > RLimit); 
    // Convert back to signed and return result 
    return (int32)iran + min; 

#else 
    // 64 bit integers not available. Use modulo method 
    uint32 interval;     // Length of interval 
    uint32 bran;      // Random bits 
    uint32 iran;      // bran/interval 
    uint32 remainder;     // bran % interval 

    interval = uint32(max - min + 1); 
    if (interval != LastInterval) { 
     // Interval length has changed. Must calculate rejection limit 
     // Reject when iran = 2^32/interval 
     // We can't make 2^32 so we use 2^32-1 and correct afterwards 
     RLimit = (uint32)0xFFFFFFFF/interval; 
     if ((uint32)0xFFFFFFFF % interval == interval - 1) RLimit++; 
    } 
    do { // Rejection loop 
     bran = BRandom(); 
     iran = bran/interval; 
     remainder = bran % interval; 
    } while (iran >= RLimit); 
    // Convert back to signed and return result 
    return (int32)remainder + min; 

#endif 
} 

Использование указанного класса довольно проста:

CRandomMersenne generator(<some_seed>); 
generator.random(); // random value [0,1] 
generator.IRandom(a,b); // random value [a,b] 

Я испытал это много раз, и она работает лучше и быстрее, чем большинство генераторов случайных чисел, у меня есть видел.

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

EDIT: автор этого кода Agner Fog, и на его сайте есть целые section для генераторов случайных чисел. Весь кредит за код идет ему.

+0

Спасибо, человек .... Он просто работал, как мне было нужно. :) – Aaron

3

Вы можете просто написать свой собственный генератор случайных чисел, как это. Качество низкое, но подходит для большей части цели.

// RAND_MAX assumed to be 32767. 
static unsigned long int next = 1; 
void srand(unsigned int seed) { next = seed; } 
int rand(void) { 
    next = next * 1103515245 + 12345; 
    return (unsigned int)(next/65536) % 32768; 
} 
+0

Спасибо. :) .. – Aaron

1

вы можете использовать:

#import <stdlib.h> 
int randomNumber = arc4random() % limiteNumber;