Added the Pseudo-Random Number Generators: Mersenne Twister and Lagged Fibonacci to My C# Application by James Pate Wiliams, Jr. with the Help of the Internet

// "Numerical Computation 2: Methods, Software,
// and Analysis" by Christoph W. Ueberhuber
// Chapter 17 Random Numbers
// "The Art of Computer Programming Volume 2"
// "Seminumerical Algorithms Second Edition"
// "Chapter 3 RANDOM NUMBERS" by Donald E. Knuth
// https://en.wikipedia.org/wiki/Mersenne_Twister

using System.Collections.Generic;

namespace SimplePRNGs
{
    class PRNGs
    {
        private long AMxn1, AMxn;
        private long AMyn1, AMyn;
        private long AMk;
        private long AMm = 34359738368;
        private long LCG0z0, LCG0z1;
        private long LCG1z0, LCG1z1;
        private long LCG2z0, LCG2z1, LCG2z2;
        private long MFG0z0, MFG0z1;
        private readonly long LCG0m = 4294967296;
        private readonly long LCG2m = 2147483647;
        private readonly List<long> AMV = new();
        private long MTindex;
        private long[] MT;
        private LaggedFibRng fibRng;

        public void SetSeedLCG0(long z0)
        {
            LCG0z0 = z0;
        }

        public void SetSeedLCG1(long z0)
        {
            LCG1z0 = z0;
        }

        public void SetSeedLCG2(long z0, long z1)
        {
            LCG2z0 = z0;
            LCG2z1 = z1;
        }

        public long LCG0()
        {
            LCG0z1 = (69069 * LCG0z0) % LCG0m;
            LCG0z0 = LCG0z1;
            return LCG0z1;
        }

        public long LCG1()
        {
            LCG1z1 = (69069 * LCG1z0 + 1) % LCG0m;
            LCG1z0 = LCG1z1;
            return LCG1z1;
        }

        public long LCG2()
        {
            LCG2z2 = (1999 * LCG2z1 + 4444 * LCG2z0) % LCG2m;
            LCG2z0 = LCG2z1;
            LCG2z1 = LCG2z2;
            return LCG2z2;
        }

        public void SetSeedMFG0(long z0, long z1)
        {
            MFG0z0 = z0;
            MFG0z1 = z1;
        }

        public long MFG0()
        {
            long MFG0z2 = (MFG0z1 + MFG0z0) % LCG0m;
            MFG0z0 = MFG0z1;
            MFG0z1 = MFG0z2;
            return MFG0z2;
        }

        public void ComputeNextXY()
        {
            AMxn1 = (3141592653 * AMxn + 2718281829) % AMm;

            if (AMxn1 < 0)
                AMxn1 += AMm;

            AMyn1 = (2718281829 * AMyn + 3141592653) % AMm;

            if (AMyn1 < 0)
                AMyn1 += AMm;
        }

        public void AMSeed(long k, long x0, long y0)
        {
            long AMTxn1, AMTxn = x0;

            AMxn = x0;
            AMyn = y0;
            AMk = k;

            for (int i = 0; i < k; i++)
            {
                AMTxn1 = (3141592653 * AMTxn + 2718281829) % AMm;

                if (AMTxn1 < 0)
                    AMTxn1 += AMm;

                AMTxn = AMTxn1;
                AMV.Add(AMTxn1);
            }
        }

        public long AlgorithmM()
        {
            ComputeNextXY();
            AMxn = AMxn1;
            AMyn = AMyn1;

            long j = (AMk * AMyn1) / AMm;
            long r = AMV[(int)j];
            
            AMV[(int)j] = AMxn1;

            if (r < 0)
                r += AMm;

            return r;
        }

        public void MTInitialization(long seed)
        {
            long f = 6364136223846793005;
            long n = 312, w = 64;

            MTindex = n;
            MT = new long[n];
            MT[0] = seed;

            for (int i = 1; i < n; i++)
                MT[i] = f * (MT[i - 1] ^ (MT[i - 1] >> (int)(w - 2))) + i;
        }

        public long MTExtractNumber()
        {
            unchecked
            {
                long n = 312;
                long c = (long)0xFFF7EEE000000000;
                long b = 0x71D67FFFEDA60000;
                long d = 0x5555555555555555;
                long u = 29, s = 17, t = 27, l = 43;

                if (MTindex == n)
                    MTTwist();

                long y = MT[MTindex];

                y ^= ((y >> (int)u) & d);
                y ^= ((y << (int)s) & b);
                y ^= ((y << (int)t) & c);
                y ^= (y >> (int)l);
                MTindex++;
                return y;
            }
        }

        public void MTTwist()
        { 
            unchecked
            {
                long n = 312, m = 156, r = 31;
                long a = (long)0xB5026F5AA96619E9;
                MTindex = n + 1;
                long lower_mask = (1 << (int)r) - 1;
                long upper_mask = ~lower_mask;

                for (int i = 0; i < n; i++)
                {
                    long x = (MT[i] & upper_mask) |
                       (MT[(i + 1) % n] & lower_mask);
                    long xA = x >> 1;

                    if (x % 2 != 0)
                        xA ^= a;

                    MT[i] = MT[(i + m) % n] ^ xA;
                }
            }

            MTindex = 0;
        }

        public void LaggedFibRngSeed(int seed)
        {
            fibRng = new LaggedFibRng(seed);
        }

        public long LaggedFibonacci(long modulus)
        {
            long lo = fibRng.Next();
            long hi = fibRng.Next();
            long rs = ((hi << 31) | lo) % modulus;

            return rs;
        }
    }
}
//https://learn.microsoft.com/en-us/archive/msdn-magazine/2016/august/test-run-lightweight-random-number-generation
// modified by current author James Pate Williams, Jr. on August 30, 2023

using System.Collections.Generic;

namespace SimplePRNGs
{
    public class LaggedFibRng
    {
        private const int k = 606; // Largest magnitude"-index"
        private const int j = 273; // Other "-index"
        private const long m = 4294967296;  // 2^32
        private readonly List<long> vals = null;
        private long seed;
        public LaggedFibRng(int seed)
        {
            vals = new List<long>();
            for (int i = 0; i < k + 1; ++i)
                vals.Add(i);
            if (seed % 2 == 0) vals[0] = 11;
            // Burn some values away
            for (int ct = 0; ct < 1000; ++ct)
            {
                long dummy = Next();
            }
        }  // ctor
        public long Next()
        {
            // (a + b) mod n = [(a mod n) + (b mod n)] mod n
            long left = vals[0] % m;    // [x-big]
            long right = vals[k - j] % m; // [x-other]
            long sum = (left + right) % m;  // prevent overflow
            if (sum < 0)
                seed = sum + m;
            else
                seed = sum;
            vals.Insert(k + 1, seed);  // Add new val at end
            vals.RemoveAt(0);  // Delete now irrelevant [0] val
            return seed;
        }
    }
}
Unknown's avatar

Author: jamespatewilliamsjr

My whole legal name is James Pate Williams, Jr. I was born in LaGrange, Georgia approximately 70 years ago. I barely graduated from LaGrange High School with low marks in June 1971. Later in June 1979, I graduated from LaGrange College with a Bachelor of Arts in Chemistry with a little over a 3 out 4 Grade Point Average (GPA). In the Spring Quarter of 1978, I taught myself how to program a Texas Instruments desktop programmable calculator and in the Summer Quarter of 1978 I taught myself Dayton BASIC (Beginner's All-purpose Symbolic Instruction Code) on LaGrange College's Data General Eclipse minicomputer. I took courses in BASIC in the Fall Quarter of 1978 and FORTRAN IV (Formula Translator IV) in the Winter Quarter of 1979. Professor Kenneth Cooper, a genius poly-scientist taught me a course in the Intel 8085 microprocessor architecture and assembly and machine language. We would hand assemble our programs and insert the resulting machine code into our crude wooden box computer which was designed and built by Professor Cooper. From 1990 to 1994 I earned a Bachelor of Science in Computer Science from LaGrange College. I had a 4 out of 4 GPA in the period 1990 to 1994. I took courses in C, COBOL, and Pascal during my BS work. After graduating from LaGrange College a second time in May 1994, I taught myself C++. In December 1995, I started using the Internet and taught myself client-server programming. I created a website in 1997 which had C and C# implementations of algorithms from the "Handbook of Applied Cryptography" by Alfred J. Menezes, et. al., and some other cryptography and number theory textbooks and treatises.

Leave a comment