[c#] CHALLENGE - Beat the time! #2

Status
Not open for further replies.
The express edition is free.

Made a few optimizations yesterday:
PHP:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Text;

namespace Hyperz.RGen
{
    public unsafe class RGen
    {
        private uint* pSeedX;
        private uint* pSeedY;

        public uint SeedX
        {
            get { return *pSeedX; }
            set { *pSeedX = value; }
        }

        public uint SeedY
        {
            get { return *pSeedY; }
            set { *pSeedY = value; }
        }

        public RGen(uint seed)
        {
            uint* pX = stackalloc uint[1];
            uint* pY = stackalloc uint[1];

            pSeedX = pX;
            pSeedY = pY;

            this.SeedX = seed;
            this.SeedY = 362436069;
        }

        public RGen(int seed) : this((uint)seed) { }

        public RGen() : this(Environment.TickCount) { }

        public uint Generate()
        {
            *pSeedX = 36969 * (*pSeedX & 65535) + (*pSeedX >> 16);
            *pSeedY = 18000 * (*pSeedY & 65535) + (*pSeedY >> 16);

            return (*pSeedX << 16) + (*pSeedY & 65535);
        }

        private void GenerateAt(uint* pDest)
        {
            *pSeedX = 36969 * (*pSeedX & 65535) + (*pSeedX >> 16);
            *pSeedY = 18000 * (*pSeedY & 65535) + (*pSeedY >> 16);

            *pDest = (*pSeedX << 16) + (*pSeedY & 65535);
        }

        public uint[] GenerateMultiple(int amount, int threadLimit = 32)
        {
            if (threadLimit == 1 || amount < threadLimit)
            {
                uint[] results = new uint[amount];

                fixed (uint* pR = results)
                {
                    for (uint* i = pR; i < pR + amount; i++) *i = this.Generate();
                }

                return results;
            }
            else
            {
                int amountPerInstance = amount / threadLimit;
                int addToLast = amount - (amountPerInstance * threadLimit);
                bool addOneToLast = (amount & 1) == 1;
                var po = new ParallelOptions() { MaxDegreeOfParallelism = threadLimit };

                uint[] results = new uint[amount];

                Parallel.For(0, threadLimit, po, num =>
                {
                    var r = new RGen(this.Generate());
                    int count = (addOneToLast && num == threadLimit - 1) ?
                        amountPerInstance + addToLast : amountPerInstance;

                    uint[] numbers = new uint[count];

                    fixed (uint* pN = numbers)
                    {
                        for (uint* i = pN; i < pN + count; i++) *i = r.Generate();
                    }

                    fixed (uint* pN = numbers, pR = results)
                    {
                        uint* pn = pN;
                        uint* pr = pR + (num * amountPerInstance);
                        uint* cnt = pn + count;

                        for (; pn < cnt; pn++, pr++) *pr = *pn;
                    }
                });

                return results;
            }
        }


        // OOOOLLLLLLDDDDDD
        /*public uint[] GenerateMultiple(int amount, int threadLimit = 32)
        {
            if (amount < threadLimit) threadLimit = 1;

            int amountPerInstance = amount / threadLimit;
            int addToLast = amount - (amountPerInstance * threadLimit);
            bool addOneToLast = (amount & 1) == 1;
            var po = new ParallelOptions() { MaxDegreeOfParallelism = threadLimit };

            uint[] results = new uint[amount];

            Parallel.For(0, threadLimit, po, num =>
            {
                var r = new RGen(this.Generate());
                int count = (addOneToLast && num == threadLimit - 1) ?
                    amountPerInstance + addToLast : amountPerInstance;

                uint[] numbers = new uint[count];

                for (int i = 0; i < count; i++) numbers[i] = r.Generate();

                lock (results) numbers.CopyTo(results, num * amountPerInstance);
            });

            return results;
        }*/
    }
}

Made the 2 seed properties pointers rather than values. The memory for those seed properties is now allocated on the stack rather than on the heap (faster). Removed the address locking from the Generate function. And finally optimized the GenerateMultiple function a bit.

Single thread: 0.69 seconds
4 threads: 0.38 seconds

I think this is as fast as I'll get this algorithm with C# :-?.
 
Status
Not open for further replies.
Back
Top