#include #include #include #include #include #include typedef __uint128_t pcg128_t; typedef struct { pcg128_t state; pcg128_t inc; } pcg_state_setseq_128; // The underlying LCG multiplier #define PCG_DEFAULT_MULTIPLIER_HIGH 2549297995355413924ULL #define PCG_DEFAULT_MULTIPLIER_LOW 4865540595714422341ULL // multiplier^-1 mod 2^128 #define PCG_DEFAULT_MULTIPLIER_INV_HIGH 566787436162029664ULL #define PCG_DEFAULT_MULTIPLIER_INV_LOW 11001107174925446285ULL // ((multiplier - 1) / 4)^-1 mod 2^126 #define PCG_DEFAULT_MULTIPLIER_DIV4_INV_HIGH 3700597123694086118ULL #define PCG_DEFAULT_MULTIPLIER_DIV4_INV_LOW 7190129193056150385ULL #define PCG_128BIT_CONSTANT(high, low) (((pcg128_t)(high) << 64) + low) #define PCG_DEFAULT_MULTIPLIER_128 \ PCG_128BIT_CONSTANT(PCG_DEFAULT_MULTIPLIER_HIGH, PCG_DEFAULT_MULTIPLIER_LOW) #define PCG_DEFAULT_MULTIPLIER_INV_128 \ PCG_128BIT_CONSTANT(PCG_DEFAULT_MULTIPLIER_INV_HIGH, PCG_DEFAULT_MULTIPLIER_INV_LOW) #define PCG_DEFAULT_MULTIPLIER_DIV4_INV_128 \ PCG_128BIT_CONSTANT(PCG_DEFAULT_MULTIPLIER_DIV4_INV_HIGH, PCG_DEFAULT_MULTIPLIER_DIV4_INV_LOW) #define PCG_DEFAULT_INCREMENT_128 \ PCG_128BIT_CONSTANT(6364136223846793005ULL, 1442695040888963407ULL) static inline uint64_t pcg_rotr_64(uint64_t value, unsigned int rot) { return (value >> rot) | (value << ((-rot) & 63)); } static inline void pcg_setseq_128_step_r(pcg_state_setseq_128 *rng) { rng->state = rng->state * PCG_DEFAULT_MULTIPLIER_128 + rng->inc; } static inline uint64_t pcg_output_xsl_rr_128_64(pcg128_t state) { return pcg_rotr_64(((uint64_t)(state >> 64u)) ^ (uint64_t)state, state >> 122u); } static inline uint64_t pcg_setseq_128_xsl_rr_64_random_r(pcg_state_setseq_128* rng) { pcg_setseq_128_step_r(rng); return pcg_output_xsl_rr_128_64(rng->state); } static inline void pcg_setseq_128_srandom_r(pcg_state_setseq_128 *rng, pcg128_t initstate, pcg128_t initseq) { rng->state = 0U; rng->inc = (initseq << 1u) | 1u; pcg_setseq_128_step_r(rng); rng->state += initstate; pcg_setseq_128_step_r(rng); } int main(int argc, char *argv[]) { if (argc != 10) { fprintf(stderr, "USAGE: %s STATE0 STATE1 ALT0 ALT1 C0 C1 D0 D1 FIXEDBITS\n", argv[0]); exit(1); } const uint64_t state0 = strtoull(argv[1], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } const uint64_t state1 = strtoull(argv[2], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } const uint64_t alt0 = strtoull(argv[3], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } const uint64_t alt1 = strtoull(argv[4], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } const uint64_t c0 = strtoull(argv[5], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } const uint64_t c1 = strtoull(argv[6], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } const uint64_t d0 = strtoull(argv[7], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } const uint64_t d1 = strtoull(argv[8], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } const uint64_t fixed_bits = strtoul(argv[9], NULL, 0); if (errno) { fprintf(stderr, "%s\n", strerror(errno)); exit(1); } // Arbitrary "stream" constants __uint128_t c = PCG_128BIT_CONSTANT(c0, c1); __uint128_t d = PCG_128BIT_CONSTANT(d0, d1); // Must be both odd or both even (can be fixed with a sign change). if (c % 2 != d % 2) { fprintf(stderr, "Constants must be both even or both odd\n"); exit(1); } // State of the first PRNG, from command line. __uint128_t state = PCG_128BIT_CONSTANT(state0, state1); // State of the second PRNG, from command line (we will use just the higher bits, and keep the lowest fixed_bits bits from the state of the first PRNG). __uint128_t alt = PCG_128BIT_CONSTANT(alt0, alt1); __uint128_t C = c << 1 | 1; __uint128_t D = d << 1 | 1; __uint128_t r = PCG_DEFAULT_MULTIPLIER_DIV4_INV_128 * ((d - c) >> 1); // This is the analogous of state in the orbit of the second PRNG. // Note that this is uselessly complicated because to clear all doubts // we want to initialize the PRNGs using pcg_setseq_128_srandom_r(), // which does some state fiddling we unwind here. __uint128_t bad_state = PCG_DEFAULT_MULTIPLIER_INV_128 * (PCG_DEFAULT_MULTIPLIER_128 * (state + C) + C - r - D) - D; // Now we keep from bad_state just the lower FIXEDBITS bits, and fill the rest using alt __uint128_t lower_bits_mask = fixed_bits == 128 ? ~(__uint128_t)0 : ((__uint128_t)1 << fixed_bits) - 1; bad_state = bad_state & lower_bits_mask | alt & ~lower_bits_mask; pcg_state_setseq_128 rng0, rng1; pcg_setseq_128_srandom_r(&rng0, state, c); pcg_setseq_128_srandom_r(&rng1, bad_state, d); for(;;) { uint64_t out = pcg_setseq_128_xsl_rr_64_random_r(&rng0); fwrite(&out, sizeof out, 1, stdout); // printf("0x%016" PRIx64 "\n", out); out = pcg_setseq_128_xsl_rr_64_random_r(&rng1); fwrite(&out, sizeof out, 1, stdout); // printf("0x%016" PRIx64 "\n", out); } }