What is the best way to generate large random numbers (bigger than 10e32)? I have seen a lot of things for better generations (mt19937
instead of rand()
) but they are still relatively limited in size. I'd prefer to stick with standard libraries if possible.
#include <iostream>
#include <random>
using std::cin;
using std::cout;
int main() {
long long userInput;
cin >> userInput;
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<long long> dist(3, userInput);
long long randomNum = dist(gen);
cout << randomNum;
};
//result of large inputs is maxed at around 10e20
To be larger than 1032 you will need 128bit generators.
There are several issues
Nothing in the standard is cryptographically secure RN. If you need cryptographically secure RN, you'll have to deal with either platform-specific calls, or roll something like AES or Chacha20
Dealing with 128bit ints is beyond standard itself, though __int128 and similar extensions are widely supported. Biggest problem is actually 128bit literals. So if you try to construct 128bits LCG like in standard, you won't be able to pass appropriate values for a, m, c etc
You might want to consider using good 64bit RN engine from standard and just glue 2 64bit random values as 128bit int, 128bit int being just a container in such case. Would work as well for cryptographically secure RN.
Just in case, below is 128bit LCG - reasonable fast, large period, very simple, works on clang and gcc
#include <cstdint>
#include <iostream>
#include <iomanip>
#define func auto
union x128
{
uint8_t c[16];
__uint128_t i;
};
std::ostream& operator << (std::ostream& os, x128 number) {
os << "0x";
for(auto k: number.c) {
os << std::hex << std::setfill('0') << std::setw(2) << uint16_t(k);
}
return os;
}
std::ostream& operator << (std::ostream& os, __uint128_t number) {
os << x128{.i=number};
return os;
}
const __uint128_t m = x128{0xdb,0x36,0x35,0x77,0x34,0xe3,0x4a,0xbb,0x00,0x50,0xd0,0x76,0x1f,0xcd,0xfc,0x15}.i; // parameters from https://arxiv.org/pdf/2001.05304.pdf
const __uint128_t c = x128{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}.i;
inline func lcg(__uint128_t xi) -> __uint128_t { // LCG
return m*xi + c;
}
const char NL = '\n';
func main() -> int {
std::cout << c << NL;
std::cout << m << NL;
std::cout << lcg(0x18290177731772ULL) << NL;
return 0;
}