stringtranslate.com

Generador congruencial permutado

Un generador congruencial permutado ( PCG ) es un algoritmo de generación de números pseudoaleatorios desarrollado en 2014 por el Dr. ME O'Neill que aplica una función de permutación de salida para mejorar las propiedades estadísticas de un generador congruencial lineal módulo 2 n . Logra un excelente rendimiento estadístico [1] [2] [3] [4] con un código pequeño y rápido, y un tamaño de estado pequeño. [5]

Un PCG se diferencia de un generador congruencial lineal clásico (LCG) en tres formas:

Es la rotación variable la que elimina el problema de un período corto en los bits de orden bajo que padecen los LCG de potencia de 2. [5] : 31–34 

Variantes

La familia PCG incluye varias variantes. El núcleo LCG está definido para anchos de entre 8 y 128 bits [ cita requerida ] , aunque solo se recomiendan 64 y 128 bits para uso práctico; los tamaños más pequeños se utilizan para pruebas estadísticas de la técnica.

La constante aditiva en el LCG se puede variar para producir diferentes flujos. La constante es un entero impar arbitrario, [6] por lo que no necesita almacenarse explícitamente; se puede utilizar la dirección de la variable de estado en sí (con el bit bajo configurado).

Existen varias transformaciones de salida diferentes definidas. Todas funcionan bien, pero algunas tienen un margen mayor que otras. [5] : 39  Se construyen a partir de los siguientes componentes:

Estos se combinan en las siguientes transformaciones de salida recomendadas, ilustradas aquí en sus tamaños más comunes:

Cada paso de estas transformaciones de salida es invertible (y, por lo tanto, uno a uno ) o un truncamiento, por lo que su composición asigna el mismo número fijo de estados de entrada a cada valor de salida. Esto preserva la equidistribución del LCG subyacente.

Por último, si se requiere una longitud de ciclo superior a 2 128 , el generador se puede ampliar con una matriz de subgeneradores. Se elige uno (en rotación) para agregarlo a la salida del generador principal y, cada vez que el estado del generador principal llega a cero, los subgeneradores se activan en un patrón que proporciona un período exponencial en el tamaño total del estado.

Código de ejemplo

El generador recomendado para la mayoría de los usuarios [5] : 43  es PCG-XSH-RR con estado de 64 bits y salida de 32 bits. Puede implementarse como:

#include <stdint.h> static uint64_t state = 0x4d595df4d0f33173 ; // O algo que dependa de la semilla static uint64_t const multiplier = 6364136223846793005u ; static uint64_t const increment = 1442695040888963407u ; // O una constante impar arbitraria               estático uint32_t rotr32 ( uint32_t x , unsigned r ) { devolver x >> r | x << ( - r & 31 ); }              uint32_t pcg32 ( void ) { uint64_t x = estado ; sin signo recuento = ( sin signo )( x >> 59 ); // 59 = 64 - 5         estado = x * multiplicador + incremento ; x ^= x >> 18 ; // 18 = (64 - 27)/2 return rotr32 (( uint32_t )( x >> 27 ), count ); // 27 = 32 - 5 }              void pcg32_init ( uint64_t semilla ) { estado = semilla + incremento ; ( void ) pcg32 (); }      

El generador aplica la transformación de salida al estado inicial en lugar del estado final para aumentar el paralelismo a nivel de instrucción disponible para maximizar el rendimiento en los procesadores superescalares modernos . [5] : 43 

Una versión ligeramente más rápida elimina el incremento, reduciendo el LCG a un generador multiplicativo ( estilo Lehmer ) con un período de solo 2 62 , y utiliza la función de salida XSH-RS más débil:

static uint64_t mcg_state = 0xcafef00dd15ea5e5u ; // Debe ser impar static uint64_t const multiplier = 6364136223846793005u ;         uint32_t pcg32_fast ( void ) { uint64_t x = mcg_state ; recuento sin signo = ( sin signo )( x >> 61 ); // 61 = 64 - 3         mcg_state = x * multiplicador ; x ^= x >> 22 ; return ( uint32_t )( x >> ( 22 + count )); // 22 = 32 - 3 - 7 }             void pcg32_fast_init ( uint64_t semilla ) { mcg_state = 2 * semilla + 1 ; ( void ) pcg32_fast (); }      

El ahorro de tiempo es mínimo, ya que la operación más costosa (la multiplicación de 64×64 bits) se mantiene, por lo que se prefiere la versión normal, salvo en casos extremos . Aun así, esta versión más rápida también pasa las pruebas estadísticas. [4]

Al ejecutarse en un procesador de 32 bits, la multiplicación de 64×64 bits debe implementarse utilizando tres operaciones de multiplicación de 32×32→64 bits. Para reducir esto a dos, existen multiplicadores de 32 bits que funcionan casi tan bien como el de 64 bits, como 0xf13283ad [6] , 0xffffffff0e703b65 o 0xf2fc5985.

Comparación con otros generadores de números pseudoaleatorios

Melissa O'Neill propone probar los PRNG aplicando pruebas estadísticas a sus variantes de tamaño reducido y determinando la cantidad mínima de bits de estado interno necesarios para pasar. [7] BigCrush de TestU01 examina suficientes datos para detectar un período de 2 35 , por lo que incluso un generador ideal requiere 36 bits de estado para pasarlo. Algunos generadores muy malos pueden pasarlo si se les da un estado lo suficientemente grande; [8] pasar a pesar de un estado pequeño es una medida de la calidad de un algoritmo y muestra cuán grande es el margen de seguridad que existe entre ese límite inferior y el tamaño del estado utilizado en aplicaciones prácticas.

PCG-RXS-M-XS (con salida de 32 bits) pasa BigCrush con 36 bits de estado (el mínimo posible), PCG-XSH-RR ( pcg32()arriba) requiere 39 y PCG-XSH-RS ( pcg32_fast()arriba) requiere 49 bits de estado. A modo de comparación, xorshift* , una de las mejores alternativas, requiere 40 bits de estado, [5] : 19  y Mersenne Twister falla a pesar de tener 19937 bits de estado. [9]

Predicción y recuperación de semillas

Se ha demostrado que es prácticamente posible (con un cálculo grande) recuperar la semilla del generador pseudoaleatorio dados 512 bytes de salida consecutivos. [10] Esto implica que es prácticamente posible predecir el resto del flujo pseudoaleatorio dados 512 bytes.

Véase también

Referencias

  1. ^ Lemire, Daniel (22 de agosto de 2017). «Prueba de generadores de números aleatorios no criptográficos: mis resultados» . Consultado el 3 de octubre de 2017 .
  2. ^ Cook, John D. (7 de julio de 2017). "Prueba del generador de números aleatorios de PCG" . Consultado el 3 de octubre de 2017 .
  3. ^ Cook, John D. (14 de agosto de 2017). "Testing RNGs with PractRand" ( Prueba de generadores de números aleatorios con PractRand) . Consultado el 3 de octubre de 2017 .
  4. ^ ab O'Neill, ME (29 de julio de 2017). "PCG Passes PractRand" (PCG aprueba PractRand) . Consultado el 3 de noviembre de 2017 .
  5. ^ abcdef O'Neill, Melissa E. (5 de septiembre de 2014). PCG: una familia de algoritmos simples, rápidos y con uso eficiente del espacio y estadísticamente buenos para la generación de números aleatorios (PDF) (informe técnico). Harvey Mudd College . HMC-CS-2014-0905.
  6. ^ ab O'Neill, ME (10 de agosto de 2017). "Crítica de las transmisiones de PCG (y también de SplitMix)" . Consultado el 3 de noviembre de 2017 .
  7. ^ O'Neill, ME (20 de agosto de 2017). "Visualización del corazón de algunos PRNG" . Consultado el 3 de noviembre de 2017 .
  8. ^ O'Neill, ME (20 de agosto de 2017). "Too Big to Fail" (Demasiado grande para quebrar) . Consultado el 3 de noviembre de 2017 .
  9. ^ L'Ecuyer, Pierre; Simard, Richard (agosto de 2007). "TestU01: biblioteca de CA para pruebas empíricas de generadores de números aleatorios" (PDF) . ACM Transactions on Mathematical Software . 33 (4): 22-1–22-40. CiteSeerX 10.1.1.499.2830 . doi :10.1145/1268776.1268777. S2CID  273446. 
  10. ^ Bouillaguet, Charles; Martinez, Florette; Sauvage, Julia (28 de septiembre de 2020). "Recuperación práctica de semillas para el generador de números pseudoaleatorios PCG". Transacciones IACR sobre criptología simétrica . 2020 (3): 175–196. doi :10.13154/tosc.v2020.i3.175-196. S2CID  222137612.

Enlaces externos