The computation xn+1 := (a * xn + c) mod m, with a = 0x11bf
, c = 0x4743
, m= 216 forms a pseudo-random number generator. Specifically, a linear congruential generator with period 211. So clearly not a high-quality PRNG, but it may be sufficient for use cases that merely require data that looks kind of random. I note that the question does not state the context in which this code is used.
The sequence of xi (here successively generated in AX
) can be reversed by using the modular multiplicative inverse ainverse like so: xn-1 = ainverse* (xn - c) mod m. In this case the modular multiplicative inverse is 0xde3f
.
Note that the value of DX
is not needed in the backwards computation, and at any point in the sequence can readily be determined from AX
if needed. The determination of the multiplicative inverse below uses a naive method based on the definition. For larger operand sizes this is hugely inefficient, one would want to use the Extended Euclidean algorithm instead.
Simple C99 code for experimenting with the computation of the multiplicative inverse and the reversing of the sequence of values in AX
:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define X_0 (0xc001)
#define ITERS (3)
uint32_t modular_inverse (uint32_t a, uint32_t m)
{
for (uint32_t x = 1; x < m; x++) {
if (((a % m) * (x % m)) % m == 1) {
return x;
}
}
printf ("no inverse found\n");
return 0;
}
uint16_t umul16_lo (uint16_t a, uint16_t b)
{
return (uint16_t)(a * b);
}
uint16_t umul16_hi (uint16_t a, uint16_t b)
{
return (uint16_t)(((uint32_t)a * b) >> 16);
}
int main (void)
{
const uint16_t a = 0x11bf; // multiplier of PRNG
const uint16_t c = 0x4743; // additive offset of PRNG
const uint32_t m = 0x10000U; // modulo of PRNG
uint16_t a_inverse;
a_inverse = modular_inverse (a, m);
printf ("a_inverse = %04x\n", a_inverse);
const uint16_t bx = a;
uint16_t dx = 0;
uint16_t ax = X_0;
printf ("starting values: ax=%04x dx=%04x bx=%04x\n", ax, dx, bx);
printf ("forward computation\n");
for (int i = 0; i < ITERS; i++) {
dx = umul16_hi (ax, bx);
ax = umul16_lo (ax, bx) + c;
}
printf ("after %d iterations: ax=%04x dx=%04x bx=%04x\n", ITERS, ax, dx, bx);
printf ("backward computation\n");
for (int i = 0; i < ITERS; i++) {
ax = umul16_lo (ax - c, a_inverse);
}
printf ("after %d iterations: ax=%04x\n", ITERS, ax);
return EXIT_SUCCESS;
}