System.Random() with seed not matching .Net or mono

I am scripting my Unity code in c# and using System.Random() with a seed to generate predictable letters for my game. I am doing the same thing on a server written in c# using .NET and was expecting the numbers to match up.

However I am getting two separate predictable results for example Unity outputs:

94 92 67

with code:

System.Random rnd = new System.Random( 8675309 );
Debug.Log( rnd.Next( 100 ) );
Debug.Log( rnd.Next( 100 ) );
Debug.Log( rnd.Next( 100 ) );

The c# server outputs:

75 99 57

with code:

System.Random rnd = new System.Random( 8675309 );
Console.WriteLine( rnd.Next( 100 ) );
Console.WriteLine( rnd.Next( 100 ) );
Console.WriteLine( rnd.Next( 100 ) );

I downloaded MonoDevelop 3.0.6 to run the server and obtained the same random numbers. I also tried running the server in dot net 3.5 and 4.0 with the same results.

I was under the impression that Unity was running under Mono and I should obtain my expected results.

Does anybody know whats going on? I am using Linq in my Unity code so I know the dot.net api has to be version 3.5 or higher.

MonoDevelop is a code editor, not something that Unity runs under; presumably you’re talking about Mono. System.Random results with a seed are not even 100% guaranteed between versions in .NET, never mind between .NET and Mono. To get 100% predictable results across platforms you will need to write your own pseudo-random generator.

The simplest pseudo random generator i know is the one that comes with borland pascal. It works pretty well. I’ve never tried the implementation in C#, but it in general it should work.

Here’s a quick adaption of the generator:

// C#
public class MyRandom
{
    private int m_Value = 0;
    public MyRandom(){}
    public MyRandom(int aSeed)
    {
        m_Value = aSeed;
    }
    private int Next()
    {
        m_Value = m_Value * 0x08088405 + 1;
        return m_Value;
    }
    public int Range(int aMin, int aMax)
    {
        return aMin + Next() % (aMax-aMin);
    }
}

Haven’t tried this implementation but it should work (unless C# complains about integer overflow ;)).

ps: it’s of course just a 32 bit random generator, but if i don’t used the wrong multiplier it shouldn’t repeat within the 32 bit limit. So it reapeats exactly after 0xFFFFFFFF times.

It just System.Random

namespace Game.Maze
{
    public class SystemRandomAdaptor : IRandom
    {
        private readonly int[] SeedArray = new int[56];
        private int inext;
        private int inextp;

        public SystemRandomAdaptor(int seed)
        {
            int num1 = 161803398 - System.Math.Abs(seed);
            SeedArray[55] = num1;
            int num2 = 1;
            for (int index1 = 1; index1 < 55; ++index1)
            {
                int index2 = 21 * index1 % 55;
                SeedArray[index2] = num2;
                num2 = num1 - num2;
                if (num2 < 0)
                    num2 += int.MaxValue;
                num1 = SeedArray[index2];
            }
            for (int index1 = 1; index1 < 5; ++index1)
            {
                for (int index2 = 1; index2 < 56; ++index2)
                {
                    SeedArray[index2] -= SeedArray[1 + (index2 + 30) % 55];
                    if (SeedArray[index2] < 0)
                        SeedArray[index2] += int.MaxValue;
                }
            }
            inext = 0;
            inextp = 21;
        }

        protected virtual double Sample()
        {
            return InternalSample() * 4.6566128752458E-10;
        }

        private int InternalSample()
        {
            int num1 = inext;
            int num2 = inextp;
            int index1;
            if ((index1 = num1 + 1) >= 56)
                index1 = 1;
            int index2;
            if ((index2 = num2 + 1) >= 56)
                index2 = 1;
            int num3 = SeedArray[index1] - SeedArray[index2];
            if (num3 < 0)
                num3 += int.MaxValue;
            SeedArray[index1] = num3;
            inext = index1;
            inextp = index2;
            return num3;
        }

        private double GetSampleForLargeRange()
        {
            int num = InternalSample();
            if (InternalSample() % 2 == 0)
                num = -num;
            return (num + 2147483646.0) / 4294967293.0;
        }

        public SystemRandomAdaptor(long seed) : this((int)seed) { }
        public int Random(int min, int max)
        {
            max += 1;
            long num = max - (long)min;
            if (num <= int.MaxValue)
                return (int)(Sample() * num) + min;
            return (int)((long)(GetSampleForLargeRange() * num) + min);
        }
    }
}

,It just using System.Random code

namespace Game.Maze
{
    public class SystemRandomAdaptor : IRandom
    {
        private readonly int[] SeedArray = new int[56];
        private int inext;
        private int inextp;

        public SystemRandomAdaptor(int seed)
        {
            int num1 = 161803398 - System.Math.Abs(seed);
            SeedArray[55] = num1;
            int num2 = 1;
            for (int index1 = 1; index1 < 55; ++index1)
            {
                int index2 = 21 * index1 % 55;
                SeedArray[index2] = num2;
                num2 = num1 - num2;
                if (num2 < 0)
                    num2 += int.MaxValue;
                num1 = SeedArray[index2];
            }
            for (int index1 = 1; index1 < 5; ++index1)
            {
                for (int index2 = 1; index2 < 56; ++index2)
                {
                    SeedArray[index2] -= SeedArray[1 + (index2 + 30) % 55];
                    if (SeedArray[index2] < 0)
                        SeedArray[index2] += int.MaxValue;
                }
            }
            inext = 0;
            inextp = 21;
        }

        protected virtual double Sample()
        {
            return InternalSample() * 4.6566128752458E-10;
        }

        private int InternalSample()
        {
            int num1 = inext;
            int num2 = inextp;
            int index1;
            if ((index1 = num1 + 1) >= 56)
                index1 = 1;
            int index2;
            if ((index2 = num2 + 1) >= 56)
                index2 = 1;
            int num3 = SeedArray[index1] - SeedArray[index2];
            if (num3 < 0)
                num3 += int.MaxValue;
            SeedArray[index1] = num3;
            inext = index1;
            inextp = index2;
            return num3;
        }

        private double GetSampleForLargeRange()
        {
            int num = InternalSample();
            if (InternalSample() % 2 == 0)
                num = -num;
            return (num + 2147483646.0) / 4294967293.0;
        }

        public SystemRandomAdaptor(long seed) : this((int)seed) { }
        public int Random(int min, int max)
        {
            max += 1;
            long num = max - (long)min;
            if (num <= int.MaxValue)
                return (int)(Sample() * num) + min;
            return (int)((long)(GetSampleForLargeRange() * num) + min);
        }
    }
}