He visto este generador de números pseudoaleatorios para usar en sombreadores a los que se hace referencia aquí y allá en la web :
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
Se le llama "canónico" o "una frase que encontré en la web en alguna parte".
¿Cuál es el origen de esta función? ¿Son los valores constantes tan arbitrarios como parecen o hay algo de arte en su selección? ¿Existe alguna discusión sobre los méritos de esta función?
EDITAR: La referencia más antigua a esta función con la que me he encontrado es este archivo de febrero de 2008 , la página original ya no está en la web. Pero allí no se habla más de eso que en cualquier otro lugar.
Respuestas:
¡Pregunta muy interesante!
Estoy tratando de resolver esto mientras escribo la respuesta :) Primero, una forma fácil de jugar: http://www.wolframalpha.com/input/?i=plot%28+mod%28+sin%28x*12.9898 +% 2B + y * 78.233% 29 + * + 43758.5453% 2C1% 29x% 3D0..2% 2C + y% 3D0..2% 29
Entonces pensemos en lo que estamos tratando de hacer aquí: Para dos coordenadas de entrada x, y devolvemos un "número aleatorio". Ahora bien, este no es un número aleatorio. Es lo mismo cada vez que ingresamos la misma x, y. ¡Es una función hash!
Lo primero que hace la función es pasar de 2d a 1d. Eso no es interesante en sí mismo, pero los números se eligen para que no se repitan normalmente. También tenemos una adición de punto flotante allí. Habrá algunos bits más de yox, pero es posible que los números se elijan correctamente para que se mezclen.
Luego, probamos una función sin () de caja negra. ¡Esto dependerá mucho de la implementación!
Por último, amplifica el error en la implementación sin () multiplicando y tomando la fracción.
No creo que esta sea una buena función hash en el caso general. El sin () es una caja negra, en la GPU, numéricamente. Debería ser posible construir uno mucho mejor tomando casi cualquier función hash y convirtiéndola. La parte difícil es convertir la operación de entero típica utilizada en el hash de la CPU en operaciones flotantes (de medio o 32 bits) o de punto fijo, pero debería ser posible.
Nuevamente, el verdadero problema con esto como función hash es que sin () es una caja negra.
fuente
El origen es probablemente el artículo: "Sobre la generación de números aleatorios, con ayuda de y = [(a + x) sin (bx)] mod 1", WJJ Rey, 22ª Reunión Europea de Estadísticos y 7ª Conferencia de Vilnius sobre Teoría de Probabilidad y Estadística matemática, agosto de 1998
EDITAR: Como no puedo encontrar una copia de este documento y la referencia "TestU01" puede no ser clara, aquí está el esquema como se describe en TestU01 en pseudo-C:
donde el único valor constante recomendado es el B1.
Tenga en cuenta que esto es para una secuencia. La conversión a un hash 'n' 1D se convierte en la cuadrícula de enteros. Entonces, supongo que alguien vio esto y convirtió 't' en una función simple f (x, y). Usando las constantes originales anteriores que produciría:
fuente
fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * (co.xy + vec2(43758.5453, SOMENUMBER))
a ajustarse a la función de la que trata el artículo.a
yb
) usados una y otra vez permanece, pero puede haber sido usado en el artículo que cita.los valores constantes son arbitrarios, especialmente porque son muy grandes y están a un par de decimales de los números primos.
un módulo sobre 1 de un seno de amplitud alta multiplicado por 4000 es una función periódica. es como una persiana de ventana o un metal corrugado hecho muy pequeño porque se multiplica por 4000 y gira en ángulo por el producto escalar.
como la función es 2-D, el producto escalar tiene el efecto de convertir la función periódica en un oblicuo con respecto a los ejes X e Y. Por una proporción de 13/79 aproximadamente. Es ineficiente, en realidad puede lograr lo mismo haciendo un seno de (13x + 79y), esto también logrará lo mismo, creo que con menos matemáticas.
Si encuentra el período de la función tanto en X como en Y, puede muestrearlo para que se vea como una onda sinusoidal simple nuevamente.
Aquí hay una imagen ampliada en el gráfico.
No sé el origen, pero es similar a muchos otros, si lo usa en gráficos a intervalos regulares, tenderá a producir patrones de muaré y podría ver que eventualmente vuelve a funcionar.
fuente
(13x + 79y)
yadot(XY, AB)
que hará exactamente lo que usted describe, ya que es el productox,y dot 13, 79 = (13x + 79y)
Tal vez sea un mapeo caótico no recurrente, entonces podría explicar muchas cosas, pero también puede ser solo una manipulación arbitraria con grandes números.
EDITAR: Básicamente, la función fract (sin (x) * 43758.5453) es una función simple tipo hash, sin (x) proporciona una interpolación sin problemas entre -1 a 1, por lo que sin (x) * 43758.5453 será una interpolación de - 43758.5453 a 43758.5453. Este es un rango bastante amplio, por lo que incluso un pequeño paso en x proporcionará un gran paso en el resultado y una gran variación en la parte fraccionaria. El "fract" es necesario para obtener valores en el rango de -0,99 ... a 0,999 .... Ahora, cuando tenemos algo como la función hash, deberíamos crear una función para el hash de producción a partir del vector. La forma más sencilla es llamar "hash" por separado para x cualquier componente y del vector de entrada. Pero luego, tendremos algunos valores simétricos. Entonces, deberíamos obtener algún valor del vector, el enfoque es encontrar un vector aleatorio y encontrar el producto "punto" para ese vector, aquí vamos: fract (sin (dot (co.xy, vec2 (12.9898,78.233))) * 43758.5453); Además, según el vector seleccionado, su longitud debe ser lo suficientemente larga para tener varios peroides de la función "sin" después de que se calcule el producto "punto".
fuente