This is an alternative, most mostly equivalent, re-implementation of C#'s
Random::Next
.
This works by keeping everything in equations of the form a * Seed + b mod p
.
You can resolve
these equations for any Seed
to get the output of some
(new Random(Seed).Next...)
.
You can do algebra on the equations to find other more complicated situations.
The equations can be copied to other languages easily. Just ensure you use 64
bit math. Using a 32 bit int will likely overflow and be in congruent mod
2**31 - 1
.
Get the equation that will represent the first output of Random::Next
for any Seed
.
>>> from csharp_rand import csharp_rand
>>> cs = csharp_rand()
>>> first = cs.sample_equation(0)
>>> print(first)
rand = seed * 1121899819 + 1559595546 mod 2147483647
Then running .resolve(42)
will correspond to the output of
(new Random(42)).Next()
.
>>> first.resolve(42)
1434747710
Or you can use .invert()
to go backwards, giving you the Seed
.
>>> first.invert().resolve(1434747710)
42
More complicated, obtain the 726th output of Random
from the 725th.
>>> late = 724 # 725th rand, zero indexed
>>> late_rand = cs.sample_equation(late)
>>> late_rand_plus = cs.sample_equation(late + 1)
>>> late_to_late_plus = late_rand_plus(late_rand.invert())
>>> # check for seed 42
>>> late_to_late_plus.resolve(late_rand.resolve(42)) == late_rand_plus.resolve((42))
True
>>> print(late_to_late_plus)
rand = seed * 1971396503 + 1990619591 mod 2147483647
So late_rand
represents the output of calling .Next
725 times. Then
late_rand_plus
is 726. Since both of these have the same Seed
in common, we
can invert late_rand
and compose with late_rand_plus
to get the equation
for going from the 725th .Next
to 726th .Next
.
We can check this by copying the late_to_late_plus
and late_rand.invert()
equations to a .NET playground.
using System;
public class Program
{
// next two equations take from python csharp library
private static int check(long seed) {
long ret = (seed * 1971396503 + 1990619591) % 2147483647;
return (int)ret;
}
private static int invert(long rand) {
long ret = (rand * 1433598513 + 1157387419) % 2147483647;
return (int)ret;
}
private static bool test(int Seed) {
Console.WriteLine("Testing Seed {0}: ", Seed);
var late = 724;
var prng = new Random(Seed);
for (int i = 0; i < late; i++) {
prng.Next();
}
var first = prng.Next();
var second = prng.Next();
var c = check(first);
Console.WriteLine(" Random[{0}]: {1}", late, first);
Console.WriteLine(" Random[{0}]: {1}", late + 1, second);
Console.WriteLine(" Computed: {0}", c);
Console.WriteLine(" Computed seed: {0}", invert(first));
if (c == second) {
Console.WriteLine(" Success");
return true;
}
Console.WriteLine(" Failed");
return false;
}
public static void Main() {
for (int i = 278; i < 291; i++) {
test(i);
}
}
}
Outputs:
Testing Seed 278:
Random[724]: 1558502570
Random[725]: 827201365
Computed: 827201365
Computed seed: 278
Success
Testing Seed 279:
Random[724]: 1583339083
Random[725]: 1435417286
Computed: 1435417286
Computed seed: 279
Success
...