Custom Random Generation Class

zerker24

Developer
Messages
35
Reaction score
42
Points
218
Okay, this is a little pointless lol. It was a project of mine to help myself learn a little more, and I wanted to see what you guys think. Basically it works the same as the build in random class in about EVERY language, but I looked up the algorithms and wrote everything out myself. There is a few goodies in here as well.

Features:
  • Generate a pseudo-randomized value.
  • Generate a pseudo-randomized decimal (between 0 - 1) value.
  • Generate a pseudo-randomized value between a Minimum and Maximum.
  • Shuffle any array using the Fisher-Yates shuffle.
  • Shuffle any List<T> with the Fisher-Yates shuffle.
  • Generate an array of random values.
  • Generate a List<T> of random value.

Code:
using System;
using System.Collections;
using System.Collections.Generic;

namespace Random_Generator
{
    public class ZerkRandom
    {
        private int seed = 0;
        private double lastVal = 0;
        // A, M, and C based on Java's java.util.Random
        private double a = 25214903917;
        private double m = Math.Pow(2, 48);
        private double c = 11;

        public ZerkRandom(int seed)
        {
            this.seed = seed;
            lastVal = seed;
        }

        private List<double> FindFactors(double num)
        {
            List<double> result = new List<double>();

            // Take out the 2s.
            while (num % 2 == 0)
            {
                result.Add(2);
                num /= 2;
            }

            // Take out other primes.
            long factor = 3;
            while (factor * factor <= num)
            {
                if (num % factor == 0)
                {
                    // This is a factor.
                    result.Add(factor);
                    num /= factor;
                }
                else
                {
                    // Go to the next odd number.
                    factor += 2;
                }
            }

            // If num is not 1, then whatever is left is prime.
            if (num > 1) result.Add(num);

            return result;
        }

        public void SetAMC(double a, double m, double c)
        {
            double tmpC = c;
            double tmpM = m;
            // Check if C and M are co-prime as per rule 1;
            while (tmpC != 0 && tmpM != 0)
            {
                if (tmpC > tmpM)
                    tmpC %= tmpM;
                else
                    tmpM %= tmpC;
            }
            if (Math.Max(tmpC, tmpM) != 1)
                throw new Exception("C and M must be relatively prime or co-prime.");

            //Get value of a - 1 for the next two rules
            double aTmp = a - 1;

            //Make sure aTmp is divisable by the prime factors of m
            List<double> primes = FindFactors(m);
            bool isPrime = true;

            foreach (double d in primes)
            {
                if ((aTmp % d) != 0)
                {
                    isPrime = false;
                    return;
                }
            }

            if (!isPrime)
                throw new Exception("A - 1 must be divisible by all the prime factors of M.");

            //If m is a multiple of 4, aTmp must be also.
            bool isMultiple = m % 4 == 0;
            if (isMultiple)
            {
                bool aIsMultiple = aTmp % 4 == 0;
                if (!aIsMultiple)
                    throw new Exception("If M is a multiple of 4, A - 1 must be also. ");
            }

            this.a = a;
            this.m = m;
            this.c = c;
        }

        /// <summary>
        /// Gets gets an array of the bits in the value.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <returns>a byte array of bits.</returns>
        private byte[] GetBits(double value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            BitArray bitArray = new BitArray(bytes);
            List<byte> bits = new List<byte>();
            foreach (bool b in bitArray)
                bits.Add(Convert.ToByte(b));
            return bits.ToArray();
        }

        /// <summary>
        /// Takes a set number of bits, and turns them into a int32.
        /// </summary>
        /// <param name="bits">The bits to start from.</param>
        /// <param name="startingBit">The bit to start from. Should be more than 32 bits away from the end.</param>
        /// <param name="endingBit">The bit to end on. Should be no more than 32 bits from the start.</param>
        /// <returns></returns>
        private int GetValue(byte[] bits, int startingBit, int endingBit)
        {
            string bitString = "";
            for (int i = startingBit; i < endingBit; i++)
                bitString += bits[i];
            return Convert.ToInt32(bitString, 2);
        }

        /// <summary>
        /// Generates a random number using a linear congruential generator.
        /// </summary>
        /// <returns>A double.</returns>
        public double Generate()
        {
            // Standard Linear Congruential Generator equation.
            double value = (a * lastVal + c) % m;
            // This next part just helps the program be more random.
            int rtnInt = GetValue(GetBits(value), 10, 42);
            lastVal = rtnInt;
            return rtnInt;
        }
        /// <summary>
        /// Generates a random number using a linear congruential generator.
        /// </summary>
        /// <returns>A double.</returns>
        public double Generate(bool PosativeOnly)
        {
            // Standard Linear Congruential Generator equation.
            double value = (a * lastVal + c) % m;
            // This next part just helps the program be more random.
            int rtnInt = GetValue(GetBits(value), 10, 42);
            lastVal = rtnInt;
            if (PosativeOnly)
                rtnInt = Math.Abs(rtnInt);
            return rtnInt;
        }
        /// <summary>
        /// Generates a random number using a linear congruential generator.
        /// </summary>
        /// <returns>A double between 0 and 1.</returns>
        public double GenerateDecimal()
        {

            double value = Generate(true);
            lastVal = value;
            value = value % 100;
            return value / 100;
        }
        /// <summary>
        /// Generates a random number using a linear congruential generator.
        /// </summary>
        /// <param name="min">The minimum number the generator will generate.</param>
        /// <param name="max">The highest number the generator will generate.</param>
        /// <returns>A double between the values of min and max.</returns>
        public double Generate(double min, double max)
        {
            double diffRate = max - min;
            double value = 0;
            if (min >= 0)
                value = Generate(true);
            else
                value = Generate();
            lastVal = value;
            return (value % diffRate) + min;
        }

        /// <summary>
        /// Shuffles a givin array randomly using the Fisher-Yates Shuffle.
        /// </summary>
        /// <typeparam name="T">The arrays object type.</typeparam>
        /// <param name="array">The array to shuffle.</param>
        /// <returns>A shuffled version of the supplied array.</returns>
        public T[] ShuffleArray<T>(T[] array)
        {
            T[] rtnArray = new T[array.Length];
            Array.Copy(array, rtnArray, array.Length);
            int n = rtnArray.Length;
            for (int i = 0; i < n; i++)
            {
                int r = i + (int)(GenerateDecimal() * (n - i));
                T t = rtnArray[r];
                rtnArray[r] = rtnArray[i];
                rtnArray[i] = t;
            }
            return rtnArray;
        }
        /// <summary>
        /// Shuffles a givin list randomly using the Fisher-Yates Shuffle.
        /// </summary>
        /// <typeparam name="T">The arrays object type.</typeparam>
        /// <param name="list">The list to shuffle.</param>
        /// <returns>A shuffled version of the supplied list.</returns>
        public List<T> ShuffleList<T>(List<T> list)
        {
            List<T> rtnList = new List<T>();
            T[] array = list.ToArray();
            int n = array.Length;
            for (int i = 0; i < n; i++)
            {
                int r = i + (int)(GenerateDecimal() * (n - i));
                T t = array[r];
                array[r] = array[i];
                array[i] = t;
            }
            foreach (T t in array)
                rtnList.Add(t);
            return rtnList;
        }

        /// <summary>
        /// Generates an array of values.
        /// </summary>
        /// <param name="length">The length of the return array.</param>
        /// <returns>An array of random double values.</returns>
        public double[] GenerateArray(int length)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.Generate());
            return data.ToArray();
        }
        /// <summary>
        /// Generates an array of values.
        /// </summary>
        /// <param name="length">The length of the return array.</param>
        /// <param name="min">The min value the system can generate.</param>
        /// <param name="max">The max value the system can generate.</param>
        /// <returns>An array of random double values.</returns>
        public double[] GenerateArray(int length, int min, int max)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.Generate(min, max));
            return data.ToArray();
        }
        /// <summary>
        /// Generates an array of values.
        /// </summary>
        /// <param name="length">The length of the return array.</param>
        /// <returns>An array of random double values between 0 and 1.</returns>
        public double[] GenerateDecimalArray(int length)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.GenerateDecimal());
            return data.ToArray();
        }

        /// <summary>
        /// Generates an list of values.
        /// </summary>
        /// <param name="length">The length of the return list.</param>
        /// <returns>An array of random double values.</returns>
        public List<double> GenerateList(int length)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.Generate());
            return data;
        }
        /// <summary>
        /// Generates an list of values.
        /// </summary>
        /// <param name="length">The length of the return list.</param>
        /// <param name="min">The min value the system can generate.</param>
        /// <param name="max">The max value the system can generate.</param>
        /// <returns>An list of random double values.</returns>
        public List<double> GenerateList(int length, int min, int max)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.Generate(min, max));
            return data;
        }
        /// <summary>
        /// Generates an list of values.
        /// </summary>
        /// <param name="length">The length of the return list.</param>
        /// <returns>An list of random double values between 0 and 1.</returns>
        public List<double> GenerateDecimalList(int length)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.GenerateDecimal());
            return data;
        }
    }
}
 
S

SeriousHD-

Guest
Okay, this is a little pointless lol. It was a project of mine to help myself learn a little more, and I wanted to see what you guys think. Basically it works the same as the build in random class in about EVERY language, but I looked up the algorithms and wrote everything out myself. There is a few goodies in here as well.

Features:
  • Generate a pseudo-randomized value.
  • Generate a pseudo-randomized decimal (between 0 - 1) value.
  • Generate a pseudo-randomized value between a Minimum and Maximum.
  • Shuffle any array using the Fisher-Yates shuffle.
  • Shuffle any List<T> with the Fisher-Yates shuffle.
  • Generate an array of random values.
  • Generate a List<T> of random value.

Code:
using System;
using System.Collections;
using System.Collections.Generic;

namespace Random_Generator
{
    public class ZerkRandom
    {
        private int seed = 0;
        private double lastVal = 0;
        // A, M, and C based on Java's java.util.Random
        private double a = 25214903917;
        private double m = Math.Pow(2, 48);
        private double c = 11;

        public ZerkRandom(int seed)
        {
            this.seed = seed;
            lastVal = seed;
        }

        private List<double> FindFactors(double num)
        {
            List<double> result = new List<double>();

            // Take out the 2s.
            while (num % 2 == 0)
            {
                result.Add(2);
                num /= 2;
            }

            // Take out other primes.
            long factor = 3;
            while (factor * factor <= num)
            {
                if (num % factor == 0)
                {
                    // This is a factor.
                    result.Add(factor);
                    num /= factor;
                }
                else
                {
                    // Go to the next odd number.
                    factor += 2;
                }
            }

            // If num is not 1, then whatever is left is prime.
            if (num > 1) result.Add(num);

            return result;
        }

        public void SetAMC(double a, double m, double c)
        {
            double tmpC = c;
            double tmpM = m;
            // Check if C and M are co-prime as per rule 1;
            while (tmpC != 0 && tmpM != 0)
            {
                if (tmpC > tmpM)
                    tmpC %= tmpM;
                else
                    tmpM %= tmpC;
            }
            if (Math.Max(tmpC, tmpM) != 1)
                throw new Exception("C and M must be relatively prime or co-prime.");

            //Get value of a - 1 for the next two rules
            double aTmp = a - 1;

            //Make sure aTmp is divisable by the prime factors of m
            List<double> primes = FindFactors(m);
            bool isPrime = true;

            foreach (double d in primes)
            {
                if ((aTmp % d) != 0)
                {
                    isPrime = false;
                    return;
                }
            }

            if (!isPrime)
                throw new Exception("A - 1 must be divisible by all the prime factors of M.");

            //If m is a multiple of 4, aTmp must be also.
            bool isMultiple = m % 4 == 0;
            if (isMultiple)
            {
                bool aIsMultiple = aTmp % 4 == 0;
                if (!aIsMultiple)
                    throw new Exception("If M is a multiple of 4, A - 1 must be also. ");
            }

            this.a = a;
            this.m = m;
            this.c = c;
        }

        /// <summary>
        /// Gets gets an array of the bits in the value.
        /// </summary>
        /// <param name="value">The value to convert.</param>
        /// <returns>a byte array of bits.</returns>
        private byte[] GetBits(double value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            BitArray bitArray = new BitArray(bytes);
            List<byte> bits = new List<byte>();
            foreach (bool b in bitArray)
                bits.Add(Convert.ToByte(b));
            return bits.ToArray();
        }

        /// <summary>
        /// Takes a set number of bits, and turns them into a int32.
        /// </summary>
        /// <param name="bits">The bits to start from.</param>
        /// <param name="startingBit">The bit to start from. Should be more than 32 bits away from the end.</param>
        /// <param name="endingBit">The bit to end on. Should be no more than 32 bits from the start.</param>
        /// <returns></returns>
        private int GetValue(byte[] bits, int startingBit, int endingBit)
        {
            string bitString = "";
            for (int i = startingBit; i < endingBit; i++)
                bitString += bits[i];
            return Convert.ToInt32(bitString, 2);
        }

        /// <summary>
        /// Generates a random number using a linear congruential generator.
        /// </summary>
        /// <returns>A double.</returns>
        public double Generate()
        {
            // Standard Linear Congruential Generator equation.
            double value = (a * lastVal + c) % m;
            // This next part just helps the program be more random.
            int rtnInt = GetValue(GetBits(value), 10, 42);
            lastVal = rtnInt;
            return rtnInt;
        }
        /// <summary>
        /// Generates a random number using a linear congruential generator.
        /// </summary>
        /// <returns>A double.</returns>
        public double Generate(bool PosativeOnly)
        {
            // Standard Linear Congruential Generator equation.
            double value = (a * lastVal + c) % m;
            // This next part just helps the program be more random.
            int rtnInt = GetValue(GetBits(value), 10, 42);
            lastVal = rtnInt;
            if (PosativeOnly)
                rtnInt = Math.Abs(rtnInt);
            return rtnInt;
        }
        /// <summary>
        /// Generates a random number using a linear congruential generator.
        /// </summary>
        /// <returns>A double between 0 and 1.</returns>
        public double GenerateDecimal()
        {

            double value = Generate(true);
            lastVal = value;
            value = value % 100;
            return value / 100;
        }
        /// <summary>
        /// Generates a random number using a linear congruential generator.
        /// </summary>
        /// <param name="min">The minimum number the generator will generate.</param>
        /// <param name="max">The highest number the generator will generate.</param>
        /// <returns>A double between the values of min and max.</returns>
        public double Generate(double min, double max)
        {
            double diffRate = max - min;
            double value = 0;
            if (min >= 0)
                value = Generate(true);
            else
                value = Generate();
            lastVal = value;
            return (value % diffRate) + min;
        }

        /// <summary>
        /// Shuffles a givin array randomly using the Fisher-Yates Shuffle.
        /// </summary>
        /// <typeparam name="T">The arrays object type.</typeparam>
        /// <param name="array">The array to shuffle.</param>
        /// <returns>A shuffled version of the supplied array.</returns>
        public T[] ShuffleArray<T>(T[] array)
        {
            T[] rtnArray = new T[array.Length];
            Array.Copy(array, rtnArray, array.Length);
            int n = rtnArray.Length;
            for (int i = 0; i < n; i++)
            {
                int r = i + (int)(GenerateDecimal() * (n - i));
                T t = rtnArray[r];
                rtnArray[r] = rtnArray[i];
                rtnArray[i] = t;
            }
            return rtnArray;
        }
        /// <summary>
        /// Shuffles a givin list randomly using the Fisher-Yates Shuffle.
        /// </summary>
        /// <typeparam name="T">The arrays object type.</typeparam>
        /// <param name="list">The list to shuffle.</param>
        /// <returns>A shuffled version of the supplied list.</returns>
        public List<T> ShuffleList<T>(List<T> list)
        {
            List<T> rtnList = new List<T>();
            T[] array = list.ToArray();
            int n = array.Length;
            for (int i = 0; i < n; i++)
            {
                int r = i + (int)(GenerateDecimal() * (n - i));
                T t = array[r];
                array[r] = array[i];
                array[i] = t;
            }
            foreach (T t in array)
                rtnList.Add(t);
            return rtnList;
        }

        /// <summary>
        /// Generates an array of values.
        /// </summary>
        /// <param name="length">The length of the return array.</param>
        /// <returns>An array of random double values.</returns>
        public double[] GenerateArray(int length)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.Generate());
            return data.ToArray();
        }
        /// <summary>
        /// Generates an array of values.
        /// </summary>
        /// <param name="length">The length of the return array.</param>
        /// <param name="min">The min value the system can generate.</param>
        /// <param name="max">The max value the system can generate.</param>
        /// <returns>An array of random double values.</returns>
        public double[] GenerateArray(int length, int min, int max)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.Generate(min, max));
            return data.ToArray();
        }
        /// <summary>
        /// Generates an array of values.
        /// </summary>
        /// <param name="length">The length of the return array.</param>
        /// <returns>An array of random double values between 0 and 1.</returns>
        public double[] GenerateDecimalArray(int length)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.GenerateDecimal());
            return data.ToArray();
        }

        /// <summary>
        /// Generates an list of values.
        /// </summary>
        /// <param name="length">The length of the return list.</param>
        /// <returns>An array of random double values.</returns>
        public List<double> GenerateList(int length)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.Generate());
            return data;
        }
        /// <summary>
        /// Generates an list of values.
        /// </summary>
        /// <param name="length">The length of the return list.</param>
        /// <param name="min">The min value the system can generate.</param>
        /// <param name="max">The max value the system can generate.</param>
        /// <returns>An list of random double values.</returns>
        public List<double> GenerateList(int length, int min, int max)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.Generate(min, max));
            return data;
        }
        /// <summary>
        /// Generates an list of values.
        /// </summary>
        /// <param name="length">The length of the return list.</param>
        /// <returns>An list of random double values between 0 and 1.</returns>
        public List<double> GenerateDecimalList(int length)
        {
            List<double> data = new List<double>();
            for (int i = 0; i < length; i++)
                data.Add(this.GenerateDecimal());
            return data;
        }
    }
}
I mean it is kind of cool to see that you are learning more about C#, but it isnt necessary to post :disappointed:
 
Top