Casuale senza base temporale [chiuso]


9

I computer non creano dal nulla un numero casuale senza base, come molto probabilmente il tempo è la base universale della casualità.

Voglio che tu crei un codice che crei numeri casuali con queste regole:

  • Il tempo non può essere la base, in nessun punto del programma.
  • Non sono consentite funzioni casuali / pseudo-casuali predefinite.
  • I numeri generati possono rientrare in qualsiasi intervallo. Bene almeno due numeri interi diversi: D
  • I numeri fanno eco.

2
Non è chiaro cosa si intende per "I numeri generati possono essere compresi in qualsiasi intervallo". Vuoi dire che il programmatore è libero di scegliere un intervallo? O che devono supportare qualsiasi intervallo richiesto dall'utente? Entrambi sono problematici. Se l'utente richiede un intervallo, cosa succede se richiede numeri al di fuori dei limiti dei tipi di dati incorporati? E se il programmatore è libero di scegliere, scelgo numeri interi compresi tra 1 e 1.: D
Jonathan Van Matre

2
Avrebbe dovuto essere un codice golf ...
Mukul Kumar

Ho iniziato questa domanda come domanda di popolarità, il golf di codice sarebbe più adatto a questo?
Dadan,

@Daniel Sì, ma lascia che questa domanda sia una domanda di popolarità e pubblica una nuova domanda con il golf del codice con nuove regole (sulla generazione casuale) che sarà divertente
Mukul Kumar

1
usare internet come seme sembra barare vero?
Decano MacGregor,

Risposte:


6

JavaScript

È stato divertente!

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())

Ho scritto il Mersenne Twister in JS. Poi, ho capito che dovevo ottenere un seme da qualche parte.

Quindi, ho deciso di prenderlo dall'API Stack Exchange! (Potrei usare localStoragee incrementare un contatore, ma non è divertente.) Quindi, ho preso le 10 risposte attive più recenti, quindi ho appena preso ogni 4 o meno cifre consecutive nella risposta e le ho aggiunte.

Questi semi sono sempre diversi, poiché Stack Overflow è in costante aggiornamento (e la mia quota continua a scendere!) I numeri includono ID risposta, ID domanda, punteggi, conteggi up / downvote, rep / ID proprietario e dati wrapper (quota e simili ). In una corsa ho avuto 256845, quindi 270495, e poi 256048, ecc ...

Questo registra 10 numeri casuali di complemento a due bit a 32 bit sulla console. Uscita campione:

247701962
-601555287
1363363842
-1184801866
1761791937
-163544156
2021774189
2140443959
1764173996
-1176627822

5

Giava

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 è nel public NoTimeRandom(). Le matrici lanciate su stringhe possono confondere i nuovi programmatori, poiché i numeri sono casuali. Esempio (per char[]:) [C@4a8e91eb. Il nextmetodo viene copiato da java.util.Random.

Uscita campione:

134277366
467041052
-555611140
-1741034686
1420784423

Testiamo l'efficacia di questo rng:

Nella mia risposta a Approximate a Bell Curve , la generazione di dati che ho usato dipende da un buon rng. Eseguiamolo con questo come rng. Produzione:

inserisci qui la descrizione dell'immagine

Proprio come pensavo. Questo è un pessimo rng.


5

C

Compilare con il flag -pthread (o qualunque cosa usi il compilatore).

#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;
}

Non sono sicuro che ciò si qualifichi o meno in base allo standard "tempo non consentito", poiché utilizza sostanzialmente lo scheduler come fonte di entropia ignorando intenzionalmente la sicurezza del thread. Funziona utilizzando una funzione psuedo-casuale abbastanza semplice ( generatore di numeri casuali Lehmer ) con un seme iniziale codificato. Quindi avvia 20 thread che eseguono tutti il ​​calcolo di Lehmer con un insieme condiviso di variabili.

Sembra funzionare abbastanza bene, ecco un paio di tirature consecutive:

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

EDIT: ci ho pensato un po 'di più e ho capito che questo non è affatto basato sul tempo. Anche con uno scheduler completamente deterministico, l'entropia non proviene dalle fasce temporali, ma dal caricamento di tutti i processi in esecuzione sul sistema.

EDIT 2 Dopo aver preso ispirazione da @Quincunx pubblicando una curva a campana, ho scaricato 12 MB di casualità in un file e l'ho caricato su CAcert . Ha fallito tutti i test irriducibili, ma ha registrato un rispettabile 7.999573 su 8 nel test ENT (solo potenzialmente deterministico). Curiosamente, raddoppiare il numero di thread ha peggiorato le cose.


4

C

Genera un numero casuale nell'intervallo 0-255 prendendo il seme da https://stackoverflow.com/questions utilizzando 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);
}

Esecuzione di esempio:

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

2

C ++

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

produzione

5 numeri casuali

tre campioni
inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine


1
1o, 2o e 5o sono piuttosto vicini, lo stesso schema ripetuto in tutti e 3 gli esempi. non esattamente l'output previsto da un generatore di numeri casuali.
Izabera,

@izabera Quando si tratta di puntatori nella generazione di numeri casuali ... tutto dipende dal tuo computer (la RAM e il processore), forse l'indirizzo attualmente utilizzato da "new int" in "ptr" è attualmente in uso! Hai provato a eseguire questo codice?
Mukul Kumar

Consentitemi di aggiungere un piccolo cambiamento
Mukul Kumar

l'ho provato ora, sulla mia macchina sembra che ottenga sempre cose del genere 11230576, 0, 11206992, 0, 2053725299, che ancora non mi sembrano casuali.
Izabera,

dai un'occhiata a ideone
izabera

2

perl

Cos'è tutta questa spazzatura quando si ottengono semi su Internet? Mi sembra un tradimento ;-) Preferisco invece dare il mio seme a una funzione hash crittografica, e dare un output nell'intervallo da 0 a 2 ^ 160-1 in questo modo:

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'

Ogni volta che si ha un'entropia di qualità incerta, un modo per distribuirlo più regolarmente (ma non aumentarne la qualità!) È collegarlo a simili SHA1 o MD5 o giù di lì, come ho fatto qui. Per i semi pre-hash, ho usato pid e l'indirizzo di un riferimento casuale. Ovviamente potresti aggiungere altri input per una maggiore entropia, ad esempio su x86 puoi usare TSC - (ma il codice di assembly inline in perl è un po 'un orso, quindi l'ho saltato).

Se vuoi avere un output diverso rispetto al ragazzo sul prossimo computer, regola semplicemente "some_salt" in modo che sia una stringa di tuo gradimento. O lascialo fuori del tutto se sei un minimalista =)


Immagino che qualsiasi funzione crittografica degna del suo nome in una libreria standard utilizzi un RNG crittograficamente sicuro internamente.
duci9y

Non ne sono sicuro. Digest :: MD5 / Digest :: SHA1 produce output completamente deterministici e ripetibili, quindi per cosa serve un numero casuale?
skibrianski

Scusate! Ho appena sorvolato la tua risposta e ho pensato che stavi generando una chiave anziché un digest.
duci9y

2

Giava

La mia soluzione abusa del hashCode()metodo di Objectclasse.

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());
        }
    }
}

Uscita campione:

31859448
22101035
11593610
4580332
25736626
32157998
3804398
32440180
19905449
2772678

Motivato da altre risposte che dimostrano la casualità della soluzione, ho cambiato la mia soluzione per restituire i 16 bit centrali del intrestituito da 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();
    }
}

Ho generato un file da 19 MB (composto da 10 7 short ) e lo ho inviato a CACert . Ecco lo screenshot del risultato (è stato modificato per apparire bello, ma i numeri sono lasciati così come sono):

Risultato

Sono stato sorpreso dal risultato, dal momento che registra 7.999991 al test Entropy e supera (?) Tutti i 7 test Diehard.


2

Javascript
Generazione casuale con spostamento del mouse dell'utente

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

Ultimi cinque dati copiati:
9637090187003
7828470680762
6045869361238
4220720695015
2422653391073


1

Bash, intervallo: ints tra 0 e 1

echo -n & echo "$! % 2" | bc

Quindi vuoi dire che seleziona solo 0 o 1?

Sì. Dovrebbe soddisfare "I numeri generati possono essere all'interno di qualsiasi intervallo. Beh, almeno due diversi numeri interi: D", non dovrebbe?
Keba

Credo di si. Pensi di poterlo espandere ad una gamma più ampia?

Proprio echo -n & echo $!lo farà, ma essere una molto cattiva RNG. Puoi anche cambiare 2 con qualsiasi altro numero, ma maggiore è il numero, peggiore diventa la "casualità".
Keba

Vedo. Grazie per la spiegazione.

1

Rubino

Sfortunatamente solo per Mac. Usiamo soxper estrarre byte dal microfono (come una stringa, ahem ...), invertirlo per ottenere l'intestazione di stato alla fine (* tosse *), tagliarlo, tagliare l'intestazione, prendere l'MD5 dei blocchi , elimina i caratteri non numerici dall'hash, aggiungi insieme gli interi di grandi dimensioni rimanenti, attacca a 0.sul davanti, converti in un float, fatto.

Genera float di lunghezza variabile sull'intervallo 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

1

C

Generazione casuale tramite ID processo.

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

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

Uscita campione:

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


0

pitone

La concisione di Python non smette mai di stupire. Dato che l'utilizzo dell'immagine casuale di imgur non è apparentemente valido, ho usato una grande fonte di casualità: la chat di 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 prove:

3258789746
1899058937
3811869909
274739242
1292809118

Non veramente casuale, ma di nuovo nessuno di questi lo è.


penso che la regola 2 non consenta URL comewhatever.com/random
izabera

@izabera 2 delle altre risposte lo hanno usato?
qwr

no, stai usando esplicitamente contenuti generati casualmente. le altre risposte accedono ad alcune pagine web non casuali per ottenere un seme e quindi stampare un numero casuale.
Izabera,

@izabera Ho cambiato la mia fonte casuale. Cosa ne pensi adesso?
qwr

ora va bene: D
izabera

0

perl

Ho visto molte risposte che hanno fatto richieste HTTP, il che mi sembra dispendioso perché sotto le coperte ci sono numeri casuali che vengono trasmessi sul filo. Così ho deciso di scrivere del codice per scorrere uno a un livello inferiore:

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

Fornisce porte casuali nell'intervallo 0..65535, teoricamente. In pratica, ci sono un certo numero di porte che non vedrai mai, quindi la distribuzione è tutt'altro che perfetta. Ma è, AFAICT la minima quantità di lavoro che puoi fare per ottenere un po 'di entropia da un host remoto con una porta aperta.

PS: la gestione degli errori viene lasciata come esercizio al lettore ;-)


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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.