种子的随机数

时间:2013-06-02 08:11:28

标签: c# random random-seed

我有一个应用程序,如果我的程序使用具有基于其种子的模式的RNG,它会变得非常明显,因为它根据景观的x坐标构建了景观。虽然Random每次调用Next()时效果都很好,但每次使用相同的输入时我都需要能够获得相同的输出,因此不能依赖Next() }。相反,我尝试每次使用输入种子简单地创建一个新的Random。我知道,这不是一个好主意,它表明了。模式非常明显,具有交替的高值和低值,并且在整个景观中具有明显的整体趋势。我不想每次都制作新的发生器,但即使这样,我也会查看加密安全的RandomNumberGenerator,看看我是否至少可以暂时使用它。然而,正如预期的那样,我无法播种它,让我没有任何可重复的输出(这是RandomNumberGenerator的重点)。

简而言之,两种常见的RNG似乎都不适合我的目的。我需要能够接收一个数字并根据该值返回一个随机数,而输出中没有明显的模式。有没有其他方法可以使用上述两种,或者是否有一种我以前没用过的方法更符合我的目的?

为清楚起见,我试图编写的方法如下:

public int RandomInt(int input)
{
    int randomOutput;
    //Be random
    return randomOutput;
}

每次给出相同的input时,它将返回相同的值。

6 个答案:

答案 0 :(得分:14)

Mersenne Twister 可能会提供更好的结果。

这是一个示例实现,您应该能够相当快速地尝试:

using System;

namespace Random
{
    /* C# Version Copyright (C) 2001 Akihilo Kramot (Takel).       */
    /* C# porting from a C-program for MT19937, originaly coded by */
    /* Takuji Nishimura, considering the suggestions by            */
    /* Topher Cooper and Marc Rieffel in July-Aug. 1997.           */
    /* This library is free software under the Artistic license:   */
    /*                                                             */
    /* You can find the original C-program at                      */
    /* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html    */
    /*                                                             */

    /// <summary>
    /// Implements a Mersenne Twister Random Number Generator. This class provides the same interface
    /// as the standard System.Random number generator, plus some additional functions.
    /// </summary>

    public class MersenneTwister: System.Random
    {
        /* Period parameters */
        private const int N = 624;
        private const int M = 397;
        private const uint MATRIX_A = 0x9908b0df; /* constant vector a */
        private const uint UPPER_MASK = 0x80000000; /* most significant w-r bits */
        private const uint LOWER_MASK = 0x7fffffff; /* least significant r bits */

        /* Tempering parameters */
        private const uint TEMPERING_MASK_B = 0x9d2c5680;
        private const uint TEMPERING_MASK_C = 0xefc60000;

        private static uint TEMPERING_SHIFT_U( uint y ) { return ( y >> 11 ); }
        private static uint TEMPERING_SHIFT_S( uint y ) { return ( y << 7 ); }
        private static uint TEMPERING_SHIFT_T( uint y ) { return ( y << 15 ); }
        private static uint TEMPERING_SHIFT_L( uint y ) { return ( y >> 18 ); }

        private uint[] mt = new uint[N]; /* the array for the state vector  */

        private uint seed_;
        private short mti;

        private static uint[] mag01 = { 0x0, MATRIX_A };

        /// <summary>
        /// Create a twister with the specified seed. All sequences started with the same seed will contain
        /// the same random numbers in the same order.
        /// </summary>
        /// <param name="seed">The seed with which to start the twister.</param>

        public MersenneTwister( uint seed )
        {
            Seed = seed;
        }


        /// <summary>
        /// Create a twister seeded from the system clock to make it as random as possible.
        /// </summary>

        public MersenneTwister()
            : this( ( (uint) DateTime.Now.Ticks ) )  // A random initial seed is used.
        {
        }


        /// <summary>
        /// The seed that was used to start the random number generator.
        /// Setting the seed resets the random number generator with the new seed.
        /// All sequences started with the same seed will contain the same random numbers in the same order.
        /// </summary>

        public uint Seed
        {
            set
            {
                seed_ = value;

                /* setting initial seeds to mt[N] using         */
                /* the generator Line 25 of Table 1 in          */
                /* [KNUTH 1981, The Art of Computer Programming */
                /*    Vol. 2 (2nd Ed.), pp102]                  */

                mt[0] = seed_ & 0xffffffffU;
                for ( mti = 1; mti < N; mti++ )
                {
                    mt[mti] = ( 69069 * mt[mti - 1] ) & 0xffffffffU;
                }
            }

            get
            {
                return seed_;
            }
        }


        /// <summary>
        /// Generate a random uint.
        /// </summary>
        /// <returns>A random uint.</returns>

        protected uint GenerateUInt()
        {
            uint y;

            /* mag01[x] = x * MATRIX_A  for x=0,1 */

            if ( mti >= N ) /* generate N words at one time */
            {
                short kk;

                for ( kk = 0; kk < N - M; kk++ )
                {
                    y = ( mt[kk] & UPPER_MASK ) | ( mt[kk + 1] & LOWER_MASK );
                    mt[kk] = mt[kk + M] ^ ( y >> 1 ) ^ mag01[y & 0x1];
                }

                for ( ; kk < N - 1; kk++ )
                {
                    y = ( mt[kk] & UPPER_MASK ) | ( mt[kk + 1] & LOWER_MASK );
                    mt[kk] = mt[kk + ( M - N )] ^ ( y >> 1 ) ^ mag01[y & 0x1];
                }

                y = ( mt[N - 1] & UPPER_MASK ) | ( mt[0] & LOWER_MASK );
                mt[N - 1] = mt[M - 1] ^ ( y >> 1 ) ^ mag01[y & 0x1];

                mti = 0;
            }

            y = mt[mti++];
            y ^= TEMPERING_SHIFT_U( y );
            y ^= TEMPERING_SHIFT_S( y ) & TEMPERING_MASK_B;
            y ^= TEMPERING_SHIFT_T( y ) & TEMPERING_MASK_C;
            y ^= TEMPERING_SHIFT_L( y );

            return y;
        }


        /// <summary>
        /// Returns the next uint in the random sequence.
        /// </summary>
        /// <returns>The next uint in the random sequence.</returns>

        public virtual uint NextUInt()
        {
            return this.GenerateUInt();
        }


        /// <summary>
        /// Returns a random number between 0 and a specified maximum.
        /// </summary>
        /// <param name="maxValue">The upper bound of the random number to be generated. maxValue must be greater than or equal to zero.</param>
        /// <returns>A 32-bit unsigned integer greater than or equal to zero, and less than maxValue; that is, the range of return values includes zero but not MaxValue.</returns>

        public virtual uint NextUInt( uint maxValue )
        {
            return (uint) ( this.GenerateUInt() / ( (double) uint.MaxValue / maxValue ) );
        }


        /// <summary>
        /// Returns an unsigned random number from a specified range.
        /// </summary>
        /// <param name="minValue">The lower bound of the random number returned.</param>
        /// <param name="maxValue">The upper bound of the random number returned. maxValue must be greater than or equal to minValue.</param>
        /// <returns>A 32-bit signed integer greater than or equal to minValue and less than maxValue;
        /// that is, the range of return values includes minValue but not MaxValue.
        /// If minValue equals maxValue, minValue is returned.</returns>

        public virtual uint NextUInt( uint minValue, uint maxValue ) /* throws ArgumentOutOfRangeException */
        {
            if (minValue >= maxValue)
            {
                if (minValue == maxValue)
                {
                    return minValue;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("minValue", "NextUInt() called with minValue >= maxValue");
                }
            }

            return (uint) ( this.GenerateUInt() / ( (double) uint.MaxValue / ( maxValue - minValue ) ) + minValue );
        }


        /// <summary>
        /// Returns a nonnegative random number.
        /// </summary>
        /// <returns>A 32-bit signed integer greater than or equal to zero and less than int.MaxValue.</returns>

        public override int Next()
        {
            return (int) ( this.GenerateUInt() / 2 );
        }


        /// <summary>
        /// Returns a nonnegative random number less than the specified maximum.
        /// </summary>
        /// <param name="maxValue">The upper bound of the random number to be generated. maxValue must be greater than or equal to zero.</param>
        /// <returns>A 32-bit signed integer greater than or equal to zero, and less than maxValue;
        /// that is, the range of return values includes zero but not MaxValue.</returns>

        public override int Next( int maxValue ) /* throws ArgumentOutOfRangeException */
        {
            if ( maxValue <= 0 )
            {
                if ( maxValue == 0 )
                    return 0;
                else
                    throw new ArgumentOutOfRangeException( "maxValue", "Next() called with a negative parameter" );
            }

            return (int) ( this.GenerateUInt() / ( uint.MaxValue / maxValue ) );
        }


        /// <summary>
        /// Returns a signed random number from a specified range.
        /// </summary>
        /// <param name="minValue">The lower bound of the random number returned.</param>
        /// <param name="maxValue">The upper bound of the random number returned. maxValue must be greater than or equal to minValue.</param>
        /// <returns>A 32-bit signed integer greater than or equal to minValue and less than maxValue;
        /// that is, the range of return values includes minValue but not MaxValue.
        /// If minValue equals maxValue, minValue is returned.</returns>

        public override int Next( int minValue, int maxValue ) /* ArgumentOutOfRangeException */
        {
            if (minValue >= maxValue)
            {
                if (minValue == maxValue)
                {
                    return minValue;
                }
                else
                {
                    throw new ArgumentOutOfRangeException("minValue", "Next() called with minValue > maxValue");
                }
            }

            return (int) ( this.GenerateUInt() / ( (double) uint.MaxValue / ( maxValue - minValue ) ) + minValue );
        }


        /// <summary>
        /// Fills an array of bytes with random numbers from 0..255
        /// </summary>
        /// <param name="buffer">The array to be filled with random numbers.</param>

        public override void NextBytes( byte[] buffer ) /* throws ArgumentNullException*/
        {
            int bufLen = buffer.Length;

            if ( buffer == null )
                throw new ArgumentNullException("buffer");

            for ( int idx = 0; idx < bufLen; idx++ )
                buffer[idx] = (byte) ( this.GenerateUInt() / ( uint.MaxValue / byte.MaxValue ) );
        }


        /// <summary>
        /// Returns a double-precision random number in the range [0..1[
        /// </summary>
        /// <returns>A random double-precision floating point number greater than or equal to 0.0, and less than 1.0.</returns>

        public override double NextDouble()
        {
            return (double) this.GenerateUInt() / uint.MaxValue;
        }
    }
}

答案 1 :(得分:5)

我讨厌回答我自己的问题,但是我的一个朋友在StackOverflow上提出了这个建议,我觉得最好把它包含在这里作为后代。

要求的实际上只是一个散列函数。如果通过适当的强哈希算法运行输入并将输出转换为int,则将生成与其输入对应的随机输出值。

答案 2 :(得分:1)

如果您尝试使输出可重现,那么您只需要使用固定种子为Random 种子

您可以在程序中将此种子作为另一个输入。这样你就会知道Next返回的数字序列在程序的两次执行中是相同的(使用相同的种子)。

你每次都应该重新初始化随机生成器。

    Random rnd1 = new Random(12);
    Random rnd2 = new Random(12);

调用Next时,这两个生成器将始终输出相同的结果。它们声明的代码中的 where 并不重要。或者何时。唯一重要的是seed(此处为12)是相同的。

如果您想要另一组可重现的值,与rnd1得到的值相同,您只需要实例化rnd2

答案 3 :(得分:0)

一种可能的方法似乎是为一次运行存储random.Next()值,并将它们映射到每个输入。在数据存储上具有这些值,在下一个应用程序运行时将它们缓存,然后开始提供它们。实际上,在给定输入的情况下,您将获得相同的随机输出。

答案 4 :(得分:0)

如果你想要'同一种子 - &gt;相同的数字'。看看这个。

这很简单。

class MyRandom
{
    private static Random Rand = new Random();
    private static Dictionary<int, int> LookupTable = new Dictionary<int, int>();

    public static int RandomInt( int seed )
    {
        try
        {
            return LookupTable[ seed ];
        }
        catch ( Exception e )
        {
            int retNum = Rand.Next();
            LookupTable.Add( seed, retNum );
            return retNum;
        }
    }
}

class Program
{
    static void Main( string[] args )
    {
        Console.WriteLine( MyRandom.RandomInt( 3 ) );
        Console.WriteLine( MyRandom.RandomInt( 1 ) );
        Console.WriteLine( MyRandom.RandomInt( 3 ) );
    }
}

答案 5 :(得分:0)

Perlin Noise或更新Simplex Noise适用于景观生成。

如果我正确理解算法,它的工作原理是将不同频率的噪声梯度(随机点之间的线性插值)加在一起。我还发现了更多detailed explanation

我在Google Code上找到了一个Simplex Noise库,

实施:

// SimplexNoise for C#
// Author: Heikki Törmälä

//This is free and unencumbered software released into the public domain.

//Anyone is free to copy, modify, publish, use, compile, sell, or
//distribute this software, either in source code form or as a compiled
//binary, for any purpose, commercial or non-commercial, and by any
//means.

//In jurisdictions that recognize copyright laws, the author or authors
//of this software dedicate any and all copyright interest in the
//software to the public domain. We make this dedication for the benefit
//of the public at large and to the detriment of our heirs and
//successors. We intend this dedication to be an overt act of
//relinquishment in perpetuity of all present and future rights to this
//software under copyright law.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
//OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
//ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.

//For more information, please refer to <http://unlicense.org/>


namespace SimplexNoise
{
    /// <summary>
    /// Implementation of the Perlin simplex noise, an improved Perlin noise algorithm.
    /// Based loosely on SimplexNoise1234 by Stefan Gustavson <http://staffwww.itn.liu.se/~stegu/aqsis/aqsis-newnoise/>
    /// 
    /// </summary>
    public class Noise
    {
        /// <summary>
        /// 1D simplex noise
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        public static float Generate(float x)
        {
            int i0 = FastFloor(x);
            int i1 = i0 + 1;
            float x0 = x - i0;
            float x1 = x0 - 1.0f;

            float n0, n1;

            float t0 = 1.0f - x0*x0;
            t0 *= t0;
            n0 = t0 * t0 * grad(perm[i0 & 0xff], x0);

            float t1 = 1.0f - x1*x1;
            t1 *= t1;
            n1 = t1 * t1 * grad(perm[i1 & 0xff], x1);
            // The maximum value of this noise is 8*(3/4)^4 = 2.53125
            // A factor of 0.395 scales to fit exactly within [-1,1]
            return 0.395f * (n0 + n1);
        }

        /// <summary>
        /// 2D simplex noise
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static float Generate(float x, float y)
        {
            const float F2 = 0.366025403f; // F2 = 0.5*(sqrt(3.0)-1.0)
            const float G2 = 0.211324865f; // G2 = (3.0-Math.sqrt(3.0))/6.0

            float n0, n1, n2; // Noise contributions from the three corners

            // Skew the input space to determine which simplex cell we're in
            float s = (x+y)*F2; // Hairy factor for 2D
            float xs = x + s;
            float ys = y + s;
            int i = FastFloor(xs);
            int j = FastFloor(ys);

            float t = (float)(i+j)*G2;
            float X0 = i-t; // Unskew the cell origin back to (x,y) space
            float Y0 = j-t;
            float x0 = x-X0; // The x,y distances from the cell origin
            float y0 = y-Y0;

            // For the 2D case, the simplex shape is an equilateral triangle.
            // Determine which simplex we are in.
            int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
            if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
            else {i1=0; j1=1;}      // upper triangle, YX order: (0,0)->(0,1)->(1,1)

            // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
            // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
            // c = (3-sqrt(3))/6

            float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
            float y1 = y0 - j1 + G2;
            float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords
            float y2 = y0 - 1.0f + 2.0f * G2;

            // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
            int ii = i % 256;
            int jj = j % 256;

            // Calculate the contribution from the three corners
            float t0 = 0.5f - x0*x0-y0*y0;
            if(t0 < 0.0f) n0 = 0.0f;
            else {
                t0 *= t0;
                n0 = t0 * t0 * grad(perm[ii+perm[jj]], x0, y0); 
            }

            float t1 = 0.5f - x1*x1-y1*y1;
            if(t1 < 0.0f) n1 = 0.0f;
            else {
                t1 *= t1;
                n1 = t1 * t1 * grad(perm[ii+i1+perm[jj+j1]], x1, y1);
            }

            float t2 = 0.5f - x2*x2-y2*y2;
            if(t2 < 0.0f) n2 = 0.0f;
            else {
                t2 *= t2;
                n2 = t2 * t2 * grad(perm[ii+1+perm[jj+1]], x2, y2);
            }

            // Add contributions from each corner to get the final noise value.
            // The result is scaled to return values in the interval [-1,1].
            return 40.0f * (n0 + n1 + n2); // TODO: The scale factor is preliminary!
        }


        public static float Generate(float x, float y, float z)
        {
            // Simple skewing factors for the 3D case
            const float F3 = 0.333333333f;
            const float G3 = 0.166666667f;

            float n0, n1, n2, n3; // Noise contributions from the four corners

            // Skew the input space to determine which simplex cell we're in
            float s = (x+y+z)*F3; // Very nice and simple skew factor for 3D
            float xs = x+s;
            float ys = y+s;
            float zs = z+s;
            int i = FastFloor(xs);
            int j = FastFloor(ys);
            int k = FastFloor(zs);

            float t = (float)(i+j+k)*G3; 
            float X0 = i-t; // Unskew the cell origin back to (x,y,z) space
            float Y0 = j-t;
            float Z0 = k-t;
            float x0 = x-X0; // The x,y,z distances from the cell origin
            float y0 = y-Y0;
            float z0 = z-Z0;

            // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
            // Determine which simplex we are in.
            int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
            int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords

            /* This code would benefit from a backport from the GLSL version! */
            if(x0>=y0) {
                if(y0>=z0)
                { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order
                else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order
                else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order
                }
            else { // x0<y0
                if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order
                else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order
                else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order
            }

            // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
            // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
            // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
            // c = 1/6.

            float x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
            float y1 = y0 - j1 + G3;
            float z1 = z0 - k1 + G3;
            float x2 = x0 - i2 + 2.0f*G3; // Offsets for third corner in (x,y,z) coords
            float y2 = y0 - j2 + 2.0f*G3;
            float z2 = z0 - k2 + 2.0f*G3;
            float x3 = x0 - 1.0f + 3.0f*G3; // Offsets for last corner in (x,y,z) coords
            float y3 = y0 - 1.0f + 3.0f*G3;
            float z3 = z0 - 1.0f + 3.0f*G3;

            // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
            int ii = i % 256;
            int jj = j % 256;
            int kk = k % 256;

            // Calculate the contribution from the four corners
            float t0 = 0.6f - x0*x0 - y0*y0 - z0*z0;
            if(t0 < 0.0f) n0 = 0.0f;
            else {
                t0 *= t0;
                n0 = t0 * t0 * grad(perm[ii+perm[jj+perm[kk]]], x0, y0, z0);
            }

            float t1 = 0.6f - x1*x1 - y1*y1 - z1*z1;
            if(t1 < 0.0f) n1 = 0.0f;
            else {
                t1 *= t1;
                n1 = t1 * t1 * grad(perm[ii+i1+perm[jj+j1+perm[kk+k1]]], x1, y1, z1);
            }

            float t2 = 0.6f - x2*x2 - y2*y2 - z2*z2;
            if(t2 < 0.0f) n2 = 0.0f;
            else {
                t2 *= t2;
                n2 = t2 * t2 * grad(perm[ii+i2+perm[jj+j2+perm[kk+k2]]], x2, y2, z2);
            }

            float t3 = 0.6f - x3*x3 - y3*y3 - z3*z3;
            if(t3<0.0f) n3 = 0.0f;
            else {
                t3 *= t3;
                n3 = t3 * t3 * grad(perm[ii+1+perm[jj+1+perm[kk+1]]], x3, y3, z3);
            }

            // Add contributions from each corner to get the final noise value.
            // The result is scaled to stay just inside [-1,1]
            return 32.0f * (n0 + n1 + n2 + n3); // TODO: The scale factor is preliminary!
        }

        private static byte[] perm = new byte[512] { 151,160,137,91,90,15,
              131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
              190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
              88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
              77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
              102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
              135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
              5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
              223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
              129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
              251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
              49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
              138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
              151,160,137,91,90,15,
              131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
              190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
              88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
              77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
              102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
              135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
              5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
              223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
              129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
              251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
              49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
              138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 
            };

        private static int FastFloor(float x)
        {
            return (x > 0) ? ((int)x) : (((int)x) - 1);
        }

        private static float grad( int hash, float x )
        {
            int h = hash & 15;
            float grad = 1.0f + (h & 7);   // Gradient value 1.0, 2.0, ..., 8.0
            if ((h & 8) != 0) grad = -grad;         // Set a random sign for the gradient
            return ( grad * x );           // Multiply the gradient with the distance
        }

        private static float grad( int hash, float x, float y )
        {
            int h = hash & 7;      // Convert low 3 bits of hash code
            float u = h<4 ? x : y;  // into 8 simple gradient directions,
            float v = h<4 ? y : x;  // and compute the dot product with (x,y).
            return ((h&1) != 0 ? -u : u) + ((h&2) != 0 ? -2.0f*v : 2.0f*v);
        }

        private static float grad( int hash, float x, float y , float z ) {
            int h = hash & 15;     // Convert low 4 bits of hash code into 12 simple
            float u = h<8 ? x : y; // gradient directions, and compute dot product.
            float v = h<4 ? y : h==12||h==14 ? x : z; // Fix repeats at h = 12 to 15
            return ((h&1) != 0 ? -u : u) + ((h&2) != 0 ? -v : v);
        }

        private static float grad( int hash, float x, float y, float z, float t ) {
            int h = hash & 31;      // Convert low 5 bits of hash code into 32 simple
            float u = h<24 ? x : y; // gradient directions, and compute dot product.
            float v = h<16 ? y : z;
            float w = h<8 ? z : t;
            return ((h&1) != 0 ? -u : u) + ((h&2) != 0 ? -v : v) + ((h&4) != 0 ? -w : w);
        }
    }
}