0

I am trying to generate random long long numbers using this code in C++:

random_device rd;
default_random_engine gen(rd());

uniform_int_distribution<long long> distribution(1, llround(pow(10, 12)));
long long random_num = distribution(gen);

I just want to verify that this should generate random integers from [1, 10^12] uniformly. Is this the correct way to do it?

EDIT:

random_device rd;
mt19937_64 gen(rd());

uniform_int_distribution<long long> distribution(1, llround(pow(10, 12)));
long long random_num = distribution(gen);
bayesianpower
  • 93
  • 2
  • 8
  • 2
    Instead of `default_random_engine`, I'd use `std::mt19937`. So you know you're getting high-quality random numbers. – Aykhan Hagverdili Apr 26 '20 at 18:15
  • 2
    I'd replace the call to `pow` with a compile time constant, but that shouldn't hurt you. Also keep an eye out for the [deliberately broken `random_device` implementation](https://en.cppreference.com/w/cpp/numeric/random/random_device#Notes) in older versions of mingw. – user4581301 Apr 26 '20 at 18:17
  • @user4581301 Do you happen to know why it was deliberately broken? – Aykhan Hagverdili Apr 26 '20 at 18:19
  • @Ayxan It seems `std::mt19937` is for generating 32 bit numbers. Can I still use this to generate up to 10^12? – bayesianpower Apr 26 '20 at 18:26
  • @Ayxan Probably more reasons than I'm aware of, but a big one being the lack of a good, trustworthy, and not-licence-encumbered RNG. They made it obviously broken rather than toss in a half-assed fix that looked like it worked and resulted in vulnerable applications. – user4581301 Apr 26 '20 at 18:27
  • @bayesianpower [There is also mt19937_64](https://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine) – user4581301 Apr 26 '20 at 18:28
  • Don't use `pow` instead either implement your own function or make it a literal. `pow` sometimes gives a wrong answer due to float point precision. Look here for example: https://codeforces.com/blog/entry/1521 – Mahmood Darwish Apr 26 '20 at 18:33
  • 2
    @bayesianpower — `std::uniform_int_distribution` knows how to manage RNGs whose output range is smaller then the target range. – Pete Becker Apr 26 '20 at 18:38
  • 2
    "Can I still use this" - yes. If `uniform_int_distribution` needs more randoms bits than a single call to `mt19937` can give, it will make multiple calls. [Demo](https://godbolt.org/z/NiQdR5) – Evg Apr 26 '20 at 18:39
  • Thanks for the comments. I've edited the post to `mt19937_64`, which I guess provides higher quality random numbers. Is this satisfiable now? Also @MahmoodDarwish I thought the wrong answer was due to int casting dropping the remainders, which I'm not doing here so I think it is okay? – bayesianpower Apr 26 '20 at 18:45
  • Mixing integral and floating point numbers for no good reason is a dangerous thing. Not every integer can be represented exactly, and you might get unexpected errors. For example, `std::llround(std::pow(9, 17))` gives `16677181699666568`, whereas the `9^17 = 16677181699666569`. – Evg Apr 26 '20 at 18:52
  • Note that you are only seeding the generator / engine with a single integer. That may or may not be ok for your application. – Jesper Juhl Apr 26 '20 at 18:52

1 Answers1

1

Combining all the comments above,

  1. Prefer std::mt19937 or std::mt19937_64 to std::default_random_engine to get high-quality random numbers. You can use both generators with std::uniform_int_distribution. Distributions know how to manage generators whose output range is smaller then the target range.

  2. Instead of std::llround(std::pow(10, 12)) prefer the compile-time constant (1'000'000'000'000LL). In general, not every integer can be represented exactly, and you might get unexpected results. For example, std::llround(std::pow(9, 17)) gives 16677181699666568, whereas the 9^17 = 16677181699666569.

  3. Seeding a generator with a single number (typically, 32-bit), std::mt19937_64 gen(rd()), is the simplest thing you can do. In some situations you might want to use more bits of entropy, i.e. not just a single number, but a seed sequence. See this question for more details.

Evg
  • 25,259
  • 5
  • 41
  • 83