Aleatorio sin base de tiempo [cerrado]

9

Las computadoras no crean números aleatorios sin base alguna, ya que lo más probable es que el tiempo sea la base universal de la aleatoriedad.

Quiero que crees un código que cree números aleatorios con estas reglas:

  • No se permite que el tiempo sea la base, en ningún punto del programa.
  • No se permiten funciones aleatorias / pseudoaleatorias predefinidas.
  • Los números generados pueden estar dentro de cualquier rango. Bueno, al menos dos enteros diferentes: D
  • Los números tienen eco.
Dadan
fuente
2
No está claro qué quiere decir con "los números generados pueden estar dentro de cualquier rango". ¿Quieres decir que el codificador es libre de elegir un rango? ¿O que deben admitir cualquier rango que solicite el usuario? Ambos son problemáticos. Si el usuario solicita un rango, ¿qué sucede si solicita números fuera de los límites de los tipos de datos integrados? Y si el codificador es libre de elegir, elijo enteros entre 1 y 1.: D
Jonathan Van Matre
2
Debería haber sido un código de golf ...
Mukul Kumar
Comencé esta pregunta como una pregunta de popularidad, ¿sería mejor el código-golf para esto?
Dadan
@Daniel Sí, pero que esta pregunta sea de popularidad y publique una nueva pregunta con código de golf con nuevas reglas (sobre generación aleatoria) que será divertido
Mukul Kumar
1
Usar Internet como semilla parece una trampa, ¿no?
Dean MacGregor

Respuestas:

6

JavaScript

¡Eso fue divertido!

arr = []
index = 0

function init(seed) {
    index = 0
    arr[0] = seed
    for (var i = 1; i < 624; i ++) {
        arr[i] = (1812433253 * (arr[i-1] ^ (arr[i-1] >>> 30)) + i) | 0
    }
 }

function getNumber() {
    if (index == 0) generateNumbers()

    var y = arr[index]
    y ^= (y >>> 11)
    y ^= ((y << 7) & 2636928640)
    y ^= ((y << 15) & 4022730752)
    y ^= (y >>> 18)

    index = (index + 1) % 624
    return y
}

function generateNumbers() {
    for (var i = 0; i < 624; i ++) {
        var y = (arr[i] & 0x80000000) + (arr[(i+1) % 624] & 0x7fffffff)
        arr[i] = arr[(i + 397) % 624] ^ (y >>> 1)
        if (y % 2 != 0) arr[i] ^= 2567483615
    }
}

// let's get our seed now from the SE API
var x = new XMLHttpRequest()
x.open('GET', 'http://api.stackexchange.com/2.2/answers?pagesize=10&order=desc&sort=activity&site=stackoverflow&filter=!Sri2UzKb5mTfr.XgjE', false)
x.send(null)
// we've got the answer data, now just add up all the numbers.
// only 4 digits at a time to prevent too big of a number.
var seed = 0
var numbers = x.responseText.match(/\d{0,4}/g)
for (var i = 0; i < numbers.length; i++) seed += +numbers[i]

init(seed)
for (var i = 0; i < 10; i++) console.log(getNumber())

Escribí el Mersenne Twister en JS. Entonces, me di cuenta de que tenía que conseguir una semilla de algún lado.

Entonces, decidí que lo obtendría de la API de Stack Exchange. (Podría usar localStoragee incrementar un contador, pero eso no es divertido). Entonces, tomé las 10 respuestas activas más recientes, y luego tomé cada 4 o menos dígitos consecutivos en la respuesta y los sumé.

Estas semillas son siempre diferentes, ya que Stack Overflow se actualiza constantemente (¡y mi cuota sigue bajando!) Los números incluyen ID de respuestas, ID de preguntas, puntajes, recuentos de votos hacia arriba / hacia abajo, representantes / ID del propietario y los datos del contenedor (cuota y tal ) En una carrera obtuve 256845, luego 270495, y luego 256048, etc.

Esto registra 10 números aleatorios de dos bits de 32 bits en la consola. Salida de muestra:

247701962
-601555287
1363363842
-1184801866
1761791937
-163544156
2021774189
2140443959
1764173996
-1176627822
Pomo de la puerta
fuente
5

Java

import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;

/**
 *
 * @author Quincunx
 */
public class NoTimeRandom extends Random {

    private AtomicLong seed;

    public NoTimeRandom() {
        byte[] ba = (new String[0].toString() + new String[0].toString()
                + new String[0].toString() + new String[0].toString()
                + new String[0].toString() + new String[0].toString()).getBytes();
        int seed1 = 1;
        for (byte b : ba) {
            seed1 += b;
        }

        ba = (new String[0].toString() + new String[0].toString()
                + new String[0].toString() + new String[0].toString()
                + new String[0].toString() + new String[0].toString()).getBytes();
        long seed2 = 1;
        for (byte b : ba) {
            seed2 += b;
        }

        seed = new AtomicLong(seed1 ^ seed2);
    }

    @Override
    protected int next(int bits) {
        long oldseed, newseed;
        AtomicLong seed = this.seed;
        do {
            oldseed = seed.get();
            newseed = (oldseed * 25214903917L + 11) & 281474976710655L;
        } while (!seed.compareAndSet(oldseed, newseed));

        return (int) (newseed >>> (48 - bits));
    }

    public static void main(String[] args) {
        Random r = new NoTimeRandom();

        for (int i = 0; i < 5; i++) {
            System.out.println(r.nextInt());
        }
    }

}

La magia está en el public NoTimeRandom(). Las matrices convertidas en cadenas pueden confundir a los nuevos programadores, ya que los números son aleatorios. Muestra (para char[]:) [C@4a8e91eb. El nextmétodo se copia de java.util.Random.

Salida de muestra:

134277366
467041052
-555611140
-1741034686
1420784423

Probemos la efectividad de este rng:

En mi respuesta a Aproximate a Bell Curve , la generación de datos que utilicé depende de un buen rng. Vamos a ejecutarlo con esto como el rng. Salida:

ingrese la descripción de la imagen aquí

Justo como pense. Este es un rng bastante malo.

Justin
fuente
5

C

Compile con el indicador -pthread (o lo que sea que use su compilador).

#include <stdio.h>
#include <pthread.h>

#define m (unsigned long)2147483647
#define q (unsigned long)127773
#define a (unsigned int)16807
#define r (unsigned int)2836 

static unsigned long seed;
pthread_t t[20];
int lo, hi, done;

void *pseudorandom(void *id)
{
    while(done)
    {
        int test;
        hi = seed/q;
        lo = seed%q;
        test = a * lo - r * hi;
        if (test > 0) seed = test;
        else seed = test + m;
    }
}

main()
{
     int i;
     seed = 54321;
     done = 1;

     for(i = 0; i < 20; i++) 
     {
          pthread_create(&(t[i]), NULL, &pseudorandom, NULL);
     }

     for (i = 0; i < 10; i++) 
     {
          printf("%lu\n", seed);
     }

     done = 0;
}

No estoy seguro de si esto califica o no en base al estándar "no se permite el tiempo", porque básicamente está usando el programador como fuente de entropía al ignorar intencionalmente la seguridad del hilo. Funciona mediante el uso de una función psuedo-aleatoria bastante básica ( generador de números aleatorios de Lehmer ) con una semilla inicial codificada. Luego comienza 20 hilos que ejecutan el cálculo de Lehmer con un conjunto compartido de variables.

Parece funcionar bastante bien, aquí hay un par de carreras consecutivas:

comintern ~ $ ./a.out
821551271
198866223
670412515
4292256
561301260
1256197345
959764614
874838892
1375885882
1788849800
comintern ~ $ ./a.out
2067099631
953349057
1736873858
267798474
941322622
564797842
157852857
1263164394
399068484
2077423336

EDITAR: Pensé un poco más sobre esto y me di cuenta de que esto no está basado en el tiempo. Incluso con un planificador completamente determinista, la entropía no proviene de los segmentos de tiempo, sino de la carga de todos los procesos en ejecución en el sistema.

EDITAR 2 Después de inspirarme en @Quincunx al publicar una curva de campana, volqué 12 MB de aleatoriedad en un archivo y lo cargué en CAcert . Falló todas las pruebas acérrimas, pero registró un respetable 7.999573 de 8 en la prueba ENT (solo Potencialmente determinista). Curiosamente, duplicar el número de hilos lo empeoró.

Comintern
fuente
4

C

Genera un número aleatorio en el rango de 0-255 tomando la semilla de https://stackoverflow.com/questions usando wget.

#include <stdio.h>
main()
{
    FILE *file;
    unsigned char c,x;
    system("wget -O - https://stackoverflow.com/questions > quest.html");
    file = fopen ("quest.html", "r");
    while(c=fgetc(file) != EOF) x+=c;
    fclose(file);
    printf("%d",x);
}

Ejecución de muestra:

C:\Users\izabera>random
--2014-03-02 16:15:28--  https://stackoverflow.com/questions
Resolving stackoverflow.com... 198.252.206.140
Connecting to stackoverflow.com|198.252.206.140|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 85775 (84K) [text/html]
Saving to: `STDOUT'

100%[======================================>] 85,775      40.3K/s   in 2.1s

2014-03-02 16:15:31 (40.3 KB/s) - `-' saved [85775/85775]

15 /* <=================== THIS IS THE RANDOM NUMBER */
C:\Users\izabera>random
--2014-03-02 16:15:36--  https://stackoverflow.com/questions
Resolving stackoverflow.com... 198.252.206.140
Connecting to stackoverflow.com|198.252.206.140|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 85836 (84K) [text/html]
Saving to: `STDOUT'

100%[======================================>] 85,836      50.0K/s   in 1.7s

2014-03-02 16:15:38 (50.0 KB/s) - `-' saved [85836/85836]

76
C:\Users\izabera>random
--2014-03-02 16:15:56--  https://stackoverflow.com/questions
Resolving stackoverflow.com... 198.252.206.140
Connecting to stackoverflow.com|198.252.206.140|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 85244 (83K) [text/html]
Saving to: `STDOUT'

100%[======================================>] 85,244      36.0K/s   in 2.3s

2014-03-02 16:15:59 (36.0 KB/s) - `-' saved [85244/85244]

144
izabera
fuente
2

C ++

#include<iostream>
int main()
{
    int *ptr=new int,i=0;
    for(;i<5;i++)
    {
        std::cout<<*(ptr+i)<<'\n';
    }
    return 0;
}  

salida

5 números al azar

tres muestras
ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Mukul Kumar
fuente
1
1st, 2nd y 5th están bastante cerca, el mismo patrón se repite en los 3 ejemplos. no es exactamente la salida esperada de un generador de números aleatorios.
izabera
@izabera Cuando se trata de punteros en la generación de números aleatorios ... todo depende de su computadora (la RAM y el procesador) ¡tal vez la dirección alimentada por 'new int' en 'ptr' se esté utilizando actualmente! ¿Intentaste ejecutar este código?
Mukul Kumar
Permítanme agregar un pequeño cambio
Mukul Kumar
Lo intenté ahora, en mi máquina parece que siempre tengo cosas como 11230576, 0, 11206992, 0, 2053725299, lo que todavía no me parece aleatorio.
izabera
échale un vistazo a ideone
izabera
2

perl

¿Qué es toda esta basura con la obtención de semillas a través de Internet? A mí me suena a engaño ;-) Prefiero dar mi semilla a una función hash criptográfica, y dar una salida en el rango de 0 a 2 ^ 160-1 así:

use Digest::SHA1 qw(sha1);
use bigint;
sub r {
  $_ = \3;
  /^.*x([0-9a-f]+).$/;
  hex((unpack "H*", sha1 "some_salt".$1.$$)[0])
}
print join " ", r'

Cada vez que tenga una entropía de calidad incierta, una forma de distribuirla más regularmente (¡pero no aumentar su calidad!) Es canalizarla a SHA1 o MD5 más o menos, como he hecho aquí. Para semillas pre-hash, he usado pid y la dirección de una referencia aleatoria. Por supuesto, podría agregar otras entradas para obtener más entropía, por ejemplo, en x86 puede usar TSC - (pero incluir el código de ensamblaje en perl es un poco difícil, así que lo omití).

Si desea tener una salida diferente a la del tipo en la próxima computadora, simplemente ajuste "some_salt" para que sea una cadena de su agrado. O déjalo fuera por completo si eres minimalista =)

skibrianski
fuente
Supongo que cualquier función criptográfica que valga su nombre en una biblioteca estándar utiliza un RNG criptográficamente seguro internamente.
duci9y
No estoy seguro de eso. Digest :: MD5 / Digest :: SHA1 produce una salida completamente determinista y repetible, entonces, ¿para qué necesita un número aleatorio?
skibrianski
¡Lo siento! Simplemente volé sobre tu respuesta y pensé que estabas generando una clave en lugar de un resumen.
duci9y
2

Java

Mi solución abusa del hashCode()método de Objectclase.

class G22640 {
    static class Rand {
        public int nextInt() {
            return new Object().hashCode();
        }
    }

    public static void main(String args[]) {
        Rand r = new Rand();
        for (int i = 0; i < 10; i++) {
            System.out.println(r.nextInt());
        }
    }
}

Salida de muestra:

31859448
22101035
11593610
4580332
25736626
32157998
3804398
32440180
19905449
2772678

Motivado por otras respuestas que demuestran la aleatoriedad de la solución, cambié mi solución para devolver los 16 bits del medio intdevueltos por Object.hashCode().

import java.io.*;

class G22640 {
    static class Rand {
        public short nextShort() {
            return (short) ((new Object().hashCode() >> 8) & 0xFFFF);
        }
    }

    public static void main(String args[]) throws IOException {
        Rand r = new Rand();

        for (int i = 0; i < 10; i++) {
            System.out.println(r.nextShort());
        }

        // generateToFile("random_22640.txt");
    }

    private static void generateToFile(String fileName) throws IOException {
        Rand r = new Rand();
        BufferedOutputStream o = new BufferedOutputStream(new FileOutputStream(fileName));

        for (int i = 0; i < 10000000; i++) {
            int a = r.nextShort();
            for (int j = 0; j < 2; j++) {
                o.write(a & 0xFF);
                a >>= 8;
            }
        }

        o.flush();
        o.close();
    }
}

Generé un archivo de 19 MB (que consta de 10 7 short ) y lo envié a CACert . Aquí está la captura de pantalla del resultado (se ha editado para que se vea bien, pero los números se dejan como están):

Resultado

Me sorprendió el resultado, ya que marca 7.999991 en la prueba Entropy y pasa (?) Las 7 pruebas Diehard.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
fuente
2

Javascript
Generando al azar con el movimiento del mouse del usuario

var ranArr=[];
var random=0;
var first=second=0;
function generateR(event) {
ranArr.push(parseFloat(event.clientX+document.body.scrollLeft))
ranArr.push(parseFloat(event.clientY+document.body.scrollTop));
var len=ranArr.length;

for(var i=0;i<len;i++) {
    if(i<len/2) {

    first+=ranArr[i];
    } else {
    second += ranArr[i];
    }
}
third = second/first;
third = third+"";
console.log(third.substr(5));
}
document.onmousemove=function(event){generateR(event)};

Últimos cinco datos copiados:
9637090187003
7828470680762
6045869361238
4220720695015
2422653391073

vusan
fuente
1

Bash, rango: entradas entre 0 y 1

echo -n & echo "$! % 2" | bc
Keba
fuente
¿Entonces quiere decir que solo elige 0 o 1?
Sí. Debería cumplir "Los números generados pueden estar dentro de cualquier rango. Bueno, al menos dos enteros diferentes: D", ¿no?
Keba
Supongo que sí. ¿Crees que podrías ampliarlo a un rango mayor?
Solo echo -n & echo $!lo haré, pero será un RNG muy malo. También puede cambiar 2 con cualquier otro número, pero cuanto mayor sea el número, peor será la "aleatoriedad".
Keba
Veo. Gracias por la explicación.
1

Rubí

Lamentablemente, solo Mac. Usamos soxpara extraer bytes del micrófono (como una cadena, ejem ...), invertirlo para obtener el encabezado de estado al final (* tos *), cortarlo, cortar el encabezado, tomar el MD5 de los fragmentos , deshazte de los caracteres no numéricos del hash, suma los enteros más grandes restantes, pega un 0.frente, conviértelos en un flotador, listo.

Genera flotadores de longitud variable en el intervalo 0..1.

require 'open3'
require 'digest'

class InsecureRandom
  def self.random_number
    n = self.get_bytes
    .map! { |r| Digest::MD5.hexdigest(r) }
    .map! { |r| r.gsub(/[a-z]/, '') }
    .map!(&:to_i)
    .reduce(0,:+)

    "0.#{n}".to_f
  end

  private
  def self.get_bytes
    Open3.popen3('sox -d -q -e unsigned-integer -p') do |_, stdout, _|
      stdout.read(20000).reverse.split('\\').to_a.take(20)
    end
  end
end

randomish = Array.new(20) { InsecureRandom.random_number }
puts randomish
# >> 0.2333530765409607
# >> 0.17754047429753905
# >> 0.936039801228352
# >> 0.2781141892158962
# >> 0.6243140263525706
# >> 0.1583419168189452
# >> 0.2173713056635174
# >> 0.930577106355
# >> 0.11215268787922089
# >> 0.13292311877287152
# >> 0.14791818448435443
# >> 0.4864648362730452
# >> 0.5133193113765809
# >> 0.3076637743531015
# >> 0.16060112015793476
# >> 0.7294970251624926
# >> 0.18945368886946876
# >> 0.9970215825154781
# >> 0.13775531752383308
# >> 0.5794383903900283
SLD
fuente
1

C

Generando al azar usando ID de proceso.

#include <unistd.h>
#include <stdio.h>

int     main(void)
{
    int out;
    out *= out *= out = getpid();
    printf("%d\n", out % 1024);
    return (0);
}

Salida de muestra:

-767
0
769
-1008
337
-768
369
-752
-415
0
-863
784
-463
256
657
mantale
fuente
0

pitón

La concisión de Python nunca deja de sorprender. Dado que el uso de la imagen aleatoria de imgur aparentemente no es válido, he usado una gran fuente de aleatoriedad: ¡el chat de stackoverflow!

   import urllib.request

def getrand():
    req = urllib.request.Request("http://chat.stackoverflow.com/")
    response = urllib.request.urlopen(req)
    the_page = str(response.read())

    x = 1
    for char in the_page:
        x = (3*x + ord(char) + 1)%2**32

    print(x)

5 ensayos:

3258789746
1899058937
3811869909
274739242
1292809118

No es realmente al azar, pero tampoco lo son.

qwr
fuente
creo que la regla 2 no permite urls comowhatever.com/random
izabera
@izabera 2 de las otras respuestas lo usaron?
qwr
no, explícitamente estás utilizando contenido generado aleatoriamente. las otras respuestas solo acceden a alguna página web no aleatoria para obtener una semilla y luego imprimen un número aleatorio.
izabera
@izabera He cambiado mi fuente aleatoria. ¿Qué piensas de eso ahora?
qwr
ahora está bien: D
izabera
0

perl

Vi muchas respuestas que hicieron solicitudes HTTP, lo que me parece un desperdicio porque debajo de las cubiertas hay números aleatorios que se pasan por el cable. Así que decidí escribir un código para deslizar uno a un nivel inferior:

use IO::Socket::INET;
print ((sockaddr_in(getsockname(IO::Socket::INET->new(
    PeerAddr => "google.com", PeerPort => 80, Proto => "tcp"
))))[0]);

Da puertos aleatorios en el rango 0..65535, teóricamente. En la práctica, hay una serie de puertos que nunca verá, por lo que la distribución está lejos de ser perfecta. Pero lo es, AFACIA la cantidad mínima de trabajo que puede hacer para obtener algo de entropía de un host remoto que tiene un puerto abierto.

PD: el manejo de errores se deja como un ejercicio para el lector ;-)

skibrianski
fuente
0

C

// alternating two pure-RNG inspired by http://xkcd.com/221/
int getRandomNumber()
{
   static int dice_roll = 0;
   dice_roll++;
   if ((dice_roll % 2) == 1)
   {
      return 4;
   } 
   else
   {
      return 5;
   } 
}

int main(int argc, char **argv)
{
    printf("%d\n%d\n", getRandomNumber(), getRandomNumber())
    return 0;
}
VX
fuente