public static UInt[] PySeedGetStateFor(string program) { if (program.Length * 2 > MersenneTwister.N) { throw new ArgumentException($"Length of {nameof(program)} must be less than or equal to {MersenneTwister.N / 2}", nameof(program)); } Dictionary <char, double> neededRngs = new Dictionary <char, double>(); const double chancePerChar = 1 / 96D; const double correction = chancePerChar / 10D; // Calculate required RNG output for each character for (char c = (char)0; c < 96; c++) { neededRngs[c == 95 ? '\n' : (char)(c + 32)] = chancePerChar * c + correction; } UInt[] state = new UInt[MersenneTwister.N]; int i = 0; foreach (char c in program) { if (!neededRngs.TryGetValue(c, out double rng)) { continue; } (UInt a, UInt b)states = MersenneTwister.PyGetPossibleOutputs(rng); state[i++] = MersenneTwister.GetState(states.a); state[i++] = MersenneTwister.GetState(states.b); } return(state); }
public static uint GetState(UInt n) { n = MersenneTwister.UntemperR(n, MersenneTwister.L); n = MersenneTwister.UntemperL(n, MersenneTwister.T, MersenneTwister.C); n = MersenneTwister.UntemperL(n, MersenneTwister.S, MersenneTwister.B); n = MersenneTwister.UntemperR(n, MersenneTwister.U, MersenneTwister.D); return(n); }
public static UInt UntemperR(UInt n, int shift, UInt mask) { UInt cur = n; for (int accuracy = shift; accuracy < UInt.WIDTH; accuracy += shift) { cur = n ^ ((cur >> shift) & mask); } return(cur); }
public static (UInt a, UInt b) PyGetPossibleOutputs(double d) { const double k = 1UL << 53; // Maximum value of a 53-bit number + 1 const uint bMask = (1U << 26) - 1; // A binary number containing 26 1s, used to extract b from d (the last 26 bits) ULong n = (ULong)(d * k); // Convert d back into a long by multiplying it by its max value + 1 UInt b = (uint)(n & bMask) << 6; // Use bitwise AND to get b from n, then shift the bits back to the correct locations UInt a = (uint)(n >> 26) << 5; // The rest of the bits are a, so just use some shifting, then shift the bits back to the correct locations return(a, b); // Keep in mind that some bits were lost by PyRandom. Those bits don't matter to the algorithm though, so anything can go there and you'd get the same result }
public double PyRandom() { // Why 53-bit numbers..? UInt a = this.ExtractNumber() >> 5; // Remove 5 bits, 27-bit number UInt b = this.ExtractNumber() >> 6; // Remove 6 bits, 26-bit number const double k = 1UL << 53; // Maximum value of a 53-bit number + 1 ULong n = ((ulong)a << 26) + b; // Create a 53-bit number in the form ab return(n / k); // Turn n into a fraction }
public uint ExtractNumber() { if (this._index >= MersenneTwister.N) { if (this._index > MersenneTwister.N) { throw new Exception("Generator was never seeded"); } this.Twist(); } UInt y = this._mt[this._index++]; y = y ^ ((y >> MersenneTwister.U) & MersenneTwister.D); y = y ^ ((y << MersenneTwister.S) & MersenneTwister.B); y = y ^ ((y << MersenneTwister.T) & MersenneTwister.C); y = y ^ (y >> MersenneTwister.L); return(y); }
// Brute force the factor private static UInt GetFactorFromProduct(UInt product) { IEnumerable <BigInteger> Multiples(BigInteger factor, BigInteger maxMultiple) { maxMultiple /= factor; for (BigInteger i = 0; i <= maxMultiple; i++) { yield return(factor * i); } } const uint mask = 0xFFFFFFFF; foreach (BigInteger multiple in Multiples(0x5D588B65U, (ulong)0x5D588B65U * 0xFFFFFFFF).Where(m => (m & mask) == product)) { return((uint)(multiple / 0x5D588B65U)); } throw new Exception("Failed to find a factor"); }
private static UInt GetStateFromProduct(UInt product, UInt curState) => product ^ curState;
private static UInt GetProductFromFactor(UInt factor) => factor * 0x5D588B65U;
////// private static UInt GetFactorFromKey(UInt key) => key ^ (key >> 30);
private static UInt GetKeyFromFactor(UInt factor) => factor ^ (factor >> 30);
////// private static UInt GetOriginalStateFromProduct(UInt state, UInt product) => state ^ product;
public static UInt Temper(UInt n, int shift, UInt mask) => n ^ ((n << shift) & mask);
public static UInt Temper(UInt n, int shift) => n ^ (n >> shift);
/// <summary>Returns an initKey for the current state. If the first key value is incorrect, try a different <see cref="tryKey"/> to see if that works.</summary> /// <param name="tryKey">First initKey value</param> /// <param name="keyWidth">Width of the initKey. Only the first N values matter in it</param> /// <returns>A (probably working) initKey</returns> public UInt[] PyGetInitKey(uint tryKey = 0, uint keyWidth = MersenneTwister.N) { UInt[] initKey = new UInt[keyWidth]; UInt[] mt = this._mt.ToArray(); uint j = 0; uint k; // Emulate setting the state without actually setting it. This can be done mathematically for (k = Math.Max(MersenneTwister.N, (uint)initKey.Length); k > 0; k--) { j++; if (j >= initKey.Length) { j = 0; } } // Reverse the process // This is the value for mt[0] after the first loop and throughout the second loop mt[0] = mt[MersenneTwister.N - 1]; // Undo the last 'i++' that occured to set i to the last modified index (1) uint i = 1; // Undo second for loop // Hilariously enough, this looks almost exactly the same as the process used to get the state from the initKey for (k = 1; k < MersenneTwister.N; k++) { mt[i] += i; mt[i] = mt[i] ^ (mt[i - 1] ^ (mt[i - 1] >> 30)) * 0x5D588B65U; i--; if (i == 0) { i = MersenneTwister.N - 1; } } // This is the value for mt[0] mt[0] = mt[MersenneTwister.N - 1]; i = 1; j--; if (j > initKey.Length) { j = (uint)initKey.Length - 1; } // Undo first for loop and grab the initKey UInt[] origMt = new MersenneTwister(0x12BD6AAU)._mt; for (k = 1; k < Math.Max(MersenneTwister.N, (uint)initKey.Length); k++) { if (k == 1) { // initKey[j] is actually a function of initKey[j0]. There is not a single solution for it, but many solutions (finite due to integer restriction). const uint j2 = 0; // j when the first loop starts UInt mtPrev = (origMt[i] ^ (origMt[i - 1] ^ origMt[i - 1] >> 30) * 0x19660DU) + tryKey + j2; initKey[j] = mt[i] - (mtPrev ^ (mt[i - 1] ^ mt[i - 1] >> 30) * 0x19660DU) - j; mt[i] = mtPrev; } else { initKey[j] = mt[i] - (origMt[i] ^ (mt[i - 1] ^ mt[i - 1] >> 30) * 0x19660DU) - j; mt[i] = origMt[i]; } i--; j--; if (i == 0) { mt[0] = origMt[0]; i = MersenneTwister.N - 1; } if (j == uint.MaxValue) { j = (uint)initKey.Length - 1; } } return(initKey); }