2013-06-02 19 views
14

Ho un'applicazione in cui diventa estremamente evidente se il mio programma utilizza un RNG con motivi basati sul seme, poiché crea paesaggi basati sulla coordinata x del paesaggio. Mentre Random funziona bene se si chiama Next() ogni volta, ho bisogno di essere in grado di avere lo stesso output ogni volta che utilizzo lo stesso input, e quindi non posso fare affidamento su Next(). Invece, ho tentato di creare semplicemente un nuovo Random ogni volta con il seme di input. Non è una buona idea, lo so, e ha dimostrato. Gli schemi erano estremamente ovvi, con alternanza di valori alti e bassi e una tendenza generale evidente in tutto il paesaggio. Preferirei non creare nuovi generatori ogni volta, ma anche così, ho esaminato il codice crittografico sicuro RandomNumberGenerator per vedere se potevo almeno usarlo temporaneamente. Come previsto, però, non posso seminarlo, lasciandomi senza alcun tipo di output riproducibile (che è piuttosto il punto dello RandomNumberGenerator).Numero casuale da un seme

In breve, nessuno dei due RNG comuni sembra adatto al mio scopo. Devo essere in grado di prendere un numero e restituire un numero casuale basato su quel valore senza pattern evidenti nell'output. C'è un altro modo di usare i due precedenti, o c'è un terzo che non ho usato prima che sarebbe più adatto al mio scopo?

Per chiarezza, il metodo che sto cercando di scrivere sguardi in questo modo:

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

che restituirà lo stesso valore ogni volta che lo stesso input è dato.

+0

Siamo spiacenti, ma quello che è il "ingresso" a cui ti riferisci? – aquaraga

+0

L'input è un int. Ho modificato il post per includere ciò che sto cercando di scrivere. –

+0

stai dicendo che usando Random con seed, fornisci valori alti e bassi alternati? interessante, puoi usare un po 'di matematica per lisciare il risultato o definire un intervallo per il casuale in modo che il diffrent non sia così grande – Mzf

risposta

14

A Mersenne Twisterpotrebbe dare risultati migliori.

Ecco un esempio di implementazione che si dovrebbe essere in grado di provare abbastanza rapidamente:

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; 
     } 
    } 
} 
+0

Il Mersenne Twister mi dà valori molto migliori, grazie. Sto ancora sfruttando troppo gli oggetti, ma posso modificare questo codice per richiedere solo un singolo oggetto. Grazie per l'aiuto. –

+0

Questa soluzione è al momento funzionante per me, quindi la lascerò come accettata, ma se qualcuno trova che questo non si adatta a un problema simile, ho aggiunto una risposta da un mio amico che suggerisce l'uso di un hash funzione, che può adattarsi meglio alle tue esigenze. –

0

Un modo possibile sembra memorizzare random.Next() i valori per una corsa, e mapparli ad ogni ingresso. Hanno questi valori su un archivio dati, li memorizzano nella prossima esecuzione dell'applicazione e iniziano a servirli. In effetti, otterrai lo stesso risultato casuale dato un input.

+0

Sfortunatamente, questo non funzionerà, poiché ho bisogno che i valori siano gli stessi in ogni istanza del programma, poiché si tratta di uno strumento di progettazione collaborativo e tutti hanno bisogno di vedere la stessa cosa. –

1

Se si sta tentando di rendere l'output riproducibile, è sufficiente seminare Randomuna volta con un seme fisso.

Si potrebbe rendere questo seme un altro input nel programma. In questo modo saprai che la sequenza di numeri restituiti da Next sarà identica in due esecuzioni del tuo programma (che utilizzano lo stesso seme).

Si dovrebbe sicuramente non reinizializzare il generatore casuale ogni volta.

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

Questi due generatori emetterà sempre gli stessi risultati quando Next viene chiamato. Non importa dove nel codice sono dichiarati. O quando. L'unica cosa che conta è che lo seed (qui 12) sia lo stesso.

Se si desidera un altro set di valori riproducibile, identico a quello risultante da rnd1, è sufficiente creare un'istanza rnd2.

+1

Ho già un seme base. Devo anche generare diverse migliaia di numeri casuali che sono riproducibili, anche all'interno di una singola esecuzione del codice. L'inizializzazione di Random una volta con un set di seed mi impedirà di avere un valore riproducibile all'interno della stessa esecuzione. –

+1

@MikePrecup * Stai * sbagliando e il twister Mersenne non ti aiuterà – Andrei

+0

Quindi, per favore, dimmi come sto sbagliando. Il Mersenne Twister funziona in modo eccellente, anche se dovrò spogliare il codice solo per afferrare un primo valore da un seme. –

0

Se si desidera "stesso seme -> stesso numero". guarda questo.

Questo è molto semplice.

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)); 
    } 
} 
+0

Cosa succede se viene chiamato in un ordine diverso, ad esempio 1, 3, 3? 1 non sarà più lo stesso. Questo varierà tra le esecuzioni. –

5

Odio rispondere alla mia domanda, ma un mio amico ha fatto questo suggerimento off StackOverflow, e sento che sarebbe meglio includere qui per i posteri.

Ciò che viene chiesto è in realtà solo una funzione di hashing. Se si esegue l'input tramite un algoritmo di hashing forte adatto e si converte l'output in un int, verranno generati valori di output casuali corrispondenti ai rispettivi input.

+1

Rispondere alla propria domanda su StackOverflow è perfettamente OK. Puoi persino accettare la tua risposta (ma non otterrai punti reputazione per questo). –

0

Perlin Noise o più recente Simplex Noise funziona bene per la generazione del paesaggio.

Se ho capito bene l'algoritmo, funziona sommando i gradienti di rumore (interpolazione lineare tra punti casuali) di frequenze diverse. Ho anche trovato un altro detailed explanation.

ho trovato una libreria Simplex Noise su Google Code,

e l'implementazione:

// 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); 
     } 
    } 
} 
+0

Anche se funziona bene per la generazione del paesaggio, e lo sto usando in una parte separata del mio algoritmo, questo non si riferisce alla domanda. –