Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crossplatform reproducible number generator

I need a "random" number generator, which produces the same result for a given seed on Windows, Mac, Linux, iOS and Android. Now I tried std::rand and boost::random_int_generator with boost::mt19937 but sadly the result is different between Windows and Mac.

Does anyone know of a (C++) implementation, that works reliably on all platforms?

EDIT 1:

To be more specific, a diff between numbers from boost::mt19937 on Windows and Mac shows, that on Windows there are (2) additional blocks of numbers being generated. It looks really strange because the majority of numbers is the same with these blocks being only present on Windows.

EDIT 2:

boost::mt19937 works reliably on all platforms. Our problems were not a bug there.

like image 285
abergmeier Avatar asked Jun 04 '15 16:06

abergmeier


3 Answers

You might want to try PCG-Random, from http://www.pcg-random.org/

decent, fast, portable

like image 120
Severin Pappadeux Avatar answered Nov 02 '22 03:11

Severin Pappadeux


If you don't need too-high-quality RNG, you can implement it yourself as a one-liner according to description here: https://en.wikipedia.org/wiki/Linear_congruential_generator Linear congruential gens got quite a bad name recently, but for many practical purposes they're fine.

As long as you're careful with using only guaranteed-size types (uint32_t etc.), you should be fine on all the platforms.

If you need better-quality RNG, once again you can implement Mersenne Twister (https://en.wikipedia.org/wiki/Mersenne_Twister) yourself, but it will be more complicated.

Yet another way is to use AES (or any other block cypher for that matter, like Chacha20) in CTR mode (using some predefined key) as your PRNG; it will be of the best known (cryptographic) quality :-). It won't take much coding on your side, but you'd need to link AES implementation (they're widely available).

EDIT: example pseudo-code to illustrate crypto-based PRNG:

class CryptoBasedPRNG {

 uint128_t key;
 uint128_t count;

 CryptoBasedPRNG(whatever-type seed) {
   //derive key and initial counter from seed
   //  we'll be using SHA256, but any other split should do (like odd bits/even bits of seed)
   uint256_t sha = sha256(seed);
   key = low_128bits(sha);
   count = high_128bits(sha);
  }

  uint128_t random_128_bits() {
    count += 1;//with wraparound
    return aes128(key,count);//encrypting 'count' as input data for aes128 (in ECB mode, if anybody asks about mode at this point)
  }
}

Rather easy and very random.

like image 32
No-Bugs Hare Avatar answered Nov 02 '22 04:11

No-Bugs Hare


The different numbers resulted in a piece of glm code we used. They use undetermined order of argument evaluation, which is fine for nearly random purposes, but not when you want deterministic numbers (obviously). So we corrected the code for our purposes and successfully use boost::mt19937 on Windows, Mac, Linux, Android and iOS.

Sorry for the confusion.

like image 43
abergmeier Avatar answered Nov 02 '22 04:11

abergmeier