2012-03-08 7 views
5

Uno pensaría que la distribución de bytes en guids era aleatoria, o al menos muy plana. ¿Cuál es la razón por la que Guid.NewGuid siempre hace las guías que contienen un 4? cuya representación de cadena contiene un 4?¿Por qué Guid.NewGuid nunca produce un Guid que no contenga un 4?

Eso es

Guid.NewGuid(). ToString ("N"). Contiene ("4")

siempre es cierto.

Las pruebas rápidas indican que la mayoría de los bytes ocurren en aproximadamente el 85% de las guías, pero 4 ocurre en el 100%. Tal vez esto no importe, pero me encantaría saber por qué.

[Editar]
No era terriblemente claro, por lo que se corrigió para mejorar la claridad de mi pregunta.


Ejecutar esto. No exactamente profundo, pero divertido.

using System; using System.Diagnostics;

namespace ConsoleApplication1 { class Program { static bool paused, exit;

static void Main(string[] args) 
    { 
     Console.WindowHeight = (int)(0.8*Console.LargestWindowHeight); 

     var reportInterval = TimeSpan.FromSeconds(0.15); 
     WriteLine(ConsoleColor.White, "X key to exit."); 

     Guid guid; 
     byte[] bytes; 
     long guidCount = 0; 
     var counts = new long[256]; 
     var watch = Stopwatch.StartNew(); 
     var cursorPos = new CursorLocation(); 

     while (!exit) 
     { 
      if (!paused) 
      { 
       guid = Guid.NewGuid(); 
       bytes = guid.ToByteArray(); 
       ++guidCount; 

       for (int i = 0; i < 16; i++) 
       { 
        var b = bytes[i]; 
        ++counts[b]; 
       } 

       if (watch.Elapsed > reportInterval) 
       { 
        cursorPos.MoveCursor(); 
        DumpFrequencies(counts, guidCount); 
        watch.Restart(); 
       } 
      } 

      if (Console.KeyAvailable) 
      { 
       ProcessKey(Console.ReadKey()); 
      } 
     } 
    } 


    static void ProcessKey(ConsoleKeyInfo keyInfo) 
    { 
     switch (keyInfo.Key) 
     { 
      case ConsoleKey.P: 
       paused = !paused; 
       break; 
      case ConsoleKey.X: 
       exit = true; 
       break; 
     } 
    } 


    static void DumpFrequencies(long[] byteCounts, long guidCount) 
    { 
     Write("\r\n{0} GUIDs generated. Frequencies:\r\n\r\n", guidCount); 

     const int itemWidth = 9; 
     int colCount = Console.WindowWidth/(itemWidth*2); 

     for (int i = 0; i < 256; i++) 
     { 
      var f = (double)byteCounts[i]/(16 * guidCount); 
      Write(RightAdjust(itemWidth, "{0:x}", i)); 
      Write(GetFrequencyColor(f), " {0:p}".PadRight(itemWidth), f); 
      if ((i + 1) % colCount == 0) Write("\r\n"); 
     } 
    } 


    static ConsoleColor GetFrequencyColor(double f) 
    { 
     if (f < 0.003) return ConsoleColor.DarkRed; 
     if (f < 0.004) return ConsoleColor.Green; 
     if (f < 0.005) return ConsoleColor.Yellow; 
     return ConsoleColor.White; 
    } 


    static string RightAdjust(int w, string s, params object[] args) 
    { 
     if (args.Length > 0) 
      s = string.Format(s, args); 
     return s.PadLeft(w); 
    } 

    #region From my library, so I need not include that here... 
    class CursorLocation 
    { 
     public int X, Y; 
     public CursorLocation() 
     { 
      X = Console.CursorLeft; 
      Y = Console.CursorTop; 
     } 

     public void MoveCursor() 
     { 
      Console.CursorLeft = X; 
      Console.CursorTop = Y; 
     } 
    } 


    static public void Write(string s, params object[] args) 
    { 
     if (args.Length > 0) s = string.Format(s, args); 
     Console.Write(s); 
    } 


    static public void Write(ConsoleColor c, string s, params object[] args) 
    { 
     var old = Console.ForegroundColor; 
     Console.ForegroundColor = c; 
     Write(s, args); 
     Console.ForegroundColor = old; 
    } 


    static public void WriteNewline(int count = 1) 
    { 
     while (count-- > 0) Console.WriteLine(); 
    } 


    static public void WriteLine(string s, params object[] args) 
    { 
     Write(s, args); 
     Console.Write(Environment.NewLine); 
    } 


    static public void WriteLine(ConsoleColor c, string s, params object[] args) 
    { 
     Write(c, s, args); 
     Console.Write(Environment.NewLine); 
    } 
    #endregion 
} 

}

tengo que aprender cómo formatear correctamente las cosas aquí algún día. Stackoverflow es grrr-eat.

+5

[GUID no son al azar] (http://en.wikipedia.org/wiki/GUID#Algorithm). –

+0

@KonradRudolph Es por eso que era tan específico sobre la _distribución_ de bytes que son aleatorios ** o ** al menos muy planos. Sabía que no eran del todo aleatorios, aunque no por qué. –

+2

¡Deje de quemar nuestras guías! – U1199880

Respuesta

8

Los GUID no son completamente aleatorios, el lugar donde el 4 es indica el "tipo" de GUID que se está generando.

Ver http://en.wikipedia.org/wiki/Globally_unique_identifier

+1

Genial. Acabo de tropezar con esto cuando hice un control treeview con soporte para búsqueda-como-tipo. Para probar, hice árboles enormes y cuasialeatorios, usando ToString ("N") en Guid para obtener textos que podía buscar. El control muestra cuántas coincidencias hay, resalta los nodos correspondientes, desplaza la primera coincidencia a la vista y permite al usuario navegar a la siguiente/previa coincidencia (w/wrap-around). Funcionó bien, pero me sorprendió ver 100.000 coincidencias en mi árbol de 100.000 nodos cuando escribí "4". :) –

Cuestiones relacionadas