Случайно без временной основы [закрыто]


9

Компьютеры не из ниоткуда создают случайные числа без основы, поскольку, скорее всего, время является универсальной основой случайности.

Я хочу, чтобы вы создали код, который создает случайные числа с этими правилами:

  • Время не может быть основой в любой точке программы.
  • Предопределенные случайные / псевдослучайные функции не допускаются.
  • Сгенерированные числа могут быть в любом диапазоне. Ну хотя бы два разных целых числа: D
  • Числа повторяются.

2
Непонятно, что вы подразумеваете под «генерируемые числа могут быть в любом диапазоне». Вы имеете в виду, что кодер свободен в выборе диапазона? Или что они должны поддерживать любой диапазон, который запрашивает пользователь? Оба из них являются проблематичными. Если пользователь запрашивает диапазон, что если он запрашивает числа за пределами встроенных типов данных? И если кодировщик свободен в выборе, я выбираю целые числа от 1 до 1.: D
Джонатан Ван Матре

2
Должен был быть код-гольф ...
Мукул Кумар

Я начал этот вопрос как вопрос популярности, подойдет ли для этого код-гольф?
Дадан

@Daniel Да, но пусть этот вопрос будет вопросом популярности и опубликуйте новый вопрос с гольфом кода с новыми правилами (по случайной генерации), это будет весело
Mukul Kumar

1
использование интернета как семени кажется обманом, не так ли?
Дин МакГрегор,

Ответы:


6

JavaScript

Это было весело!

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

Я написал Twister Мерсенна в JS. Затем я понял, что мне нужно откуда-то получить семена.

Итак, я решил, что получу это из Stack Exchange API! (Я мог бы использовать localStorageи увеличивать счетчик, но это не весело.) Итак, я взял 10 самых последних активных ответов, а затем просто взял каждые 4 или менее последовательных цифр в ответе и добавил их.

Эти начальные значения всегда различаются, поскольку переполнение стека постоянно обновляется (и моя квота продолжает уменьшаться!). В число входят идентификаторы ответов, идентификаторы вопросов, баллы, количество повышений / понижений, количество повторений / идентификаторов владельца и данные обертки (квота и т. Д.). ). За один прогон я попал 256845, потом 270495, и 256048тд ....

Это записывает 10 случайных 32-битных чисел с двумя дополнениями на консоль. Пример вывода:

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

5

Ява

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

}

Магия в public NoTimeRandom(). Массивы, приведенные к строкам, могут запутать новых программистов, так как числа случайны. Образец (для char[]:) [C@4a8e91eb. nextМетод копируется из java.util.Random.

Пример вывода:

134277366
467041052
-555611140
-1741034686
1420784423

Давайте проверим эффективность этой рнг:

В моем ответе « Приблизительная кривая колокольчика» генерация данных, которую я использовал, зависит от хорошего качества. Давайте запустим это как rng. Вывод:

введите описание изображения здесь

Как я и думал. Это довольно паршивый рнг.


5

С

Скомпилируйте с флагом -pthread (или с тем, что использует ваш компилятор).

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

Я не уверен, соответствует ли это стандарту «время не разрешено», потому что он в основном использует планировщик в качестве источника энтропии, преднамеренно игнорируя безопасность потоков. Он работает с использованием довольно простой псевдослучайной функции ( генератора случайных чисел Лемера ) с жестко закодированным начальным начальным числом . Затем он запускает 20 потоков, которые все выполняют вычисление Лемера с общим набором переменных.

Кажется, работает довольно хорошо, вот несколько последовательных прогонов:

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

РЕДАКТИРОВАТЬ: Дайте немного больше думать и понял, что это не на основе времени вообще. Даже с полностью детерминированным планировщиком энтропия не исходит из временных интервалов - она ​​зависит от загрузки всех запущенных процессов в системе.

РЕДАКТИРОВАТЬ 2 После того, как @Quincunx опубликовал кривую колокольчика, я скопировал 12 МБ случайности в файл и загрузил его в CAcert . Он провалил все несгибаемые тесты, но набрал приличный 7.999573 из 8 в тесте ЛОР (только потенциально детерминированный). Любопытно, что удвоение количества потоков ухудшило ситуацию.


4

С

Он генерирует случайное число в диапазоне 0-255, беря начальное число из https://stackoverflow.com/questions, используя 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);
}

Образец прогона:

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

вывод

любые 5 случайных чисел

три образца
введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь


1
1-й, 2-й и 5-й довольно близки, один и тот же шаблон повторяется во всех трех примерах. не совсем ожидаемый результат от генератора случайных чисел.
Изабера

@izabera Когда дело доходит до указателей при генерации случайных чисел ... все зависит от вашего компьютера (ОЗУ и процессор), может быть, в настоящее время используется адрес, передаваемый 'new int' в 'ptr'! Вы пытались запустить этот код?
Мукул Кумар

Позвольте мне добавить небольшое изменение
Мукул Кумар

я попробовал это сейчас, на моей машине кажется, что я всегда получаю такие вещи 11230576, 0, 11206992, 0, 2053725299, которые мне пока не кажутся случайными.
Изабера

проверить это в ideone
изабера

2

Perl

Что за хлам с получением семян через интернет? Звучит как измена для меня ;-) Я предпочитаю вместо этого отдавать свое начальное значение криптографической хеш-функции и выводить в диапазоне от 0 до 2 ^ 160-1 примерно так:

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'

В любое время, когда у вас есть энтропия неопределенного качества, способ распределять ее более регулярно (но не повышать ее качество!) - это направить ее на SHA1 или MD5 или около того, как я это сделал здесь. Для предварительного хэширования я использовал pid и адрес случайной ссылки. Конечно, вы можете добавить другие входные данные для большей энтропии, например, на x86 вы можете использовать TSC - (но встраивание ассемблерного кода в perl - это немного не так, поэтому я его пропустил).

Если вы хотите, чтобы вывод на другой компьютер был другим, просто настройте «some_salt» так, чтобы он вам нравился. Или вообще не включайте, если вы минималист =)


Я предполагаю, что любая криптографическая функция, имеющая свое название в стандартной библиотеке, использует криптографически безопасный ГСЧ внутри.
duci9y

Я не уверен в этом. Digest :: MD5 / Digest :: SHA1 производят полностью детерминированный, воспроизводимый вывод, так для чего ему нужно случайное число?
Скибрянски

Сожалею! Я просто пролетел над вашим ответом и подумал, что вы генерируете ключ вместо дайджеста.
duci9y

2

Ява

Мое решение злоупотребляет hashCode()методом Objectкласса.

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

Пример вывода:

31859448
22101035
11593610
4580332
25736626
32157998
3804398
32440180
19905449
2772678

По мотивам другого ответа, демонстрирующего случайность решения, я изменил свое решение, чтобы вернуть средние 16 битов intвозвращенного значения 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();
    }
}

Я сгенерировал файл размером 19 МБ (состоящий из 10 7 short ) и отправил его в CACert . Вот скриншот результата (он был отредактирован, чтобы хорошо выглядеть, но цифры остались без изменений):

Результат

Я был удивлен результатом, так как он проверяет 7.999991 на тесте Entropy и проходит (?) Все 7 тестов Diehard.


2

Javascript
Генерация случайных с движением мыши

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

Последние пять скопированных данных:
9637090187003
7828470680762
6045869361238
4220720695015
2422653391073


1

Bash, диапазон: целые числа от 0 до 1

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

То есть, вы выбираете только 0 или 1?

Ага. Должно быть выполнено "Сгенерированные числа могут быть в любом диапазоне. Ну, по крайней мере, два разных целых числа: D", не так ли?
Кеба

Полагаю, что так. Как вы думаете, вы могли бы расширить его до большего диапазона?

Просто echo -n & echo $!сделаю, но будет очень плохой ГСЧ. Вы также можете изменить 2 на любое другое число, но чем больше число, тем хуже становится «случайность».
Кеба

Понимаю. Спасибо за объяснение.

1

Рубин

К сожалению, только Mac. Мы используем, soxчтобы вытащить байты из микрофона (как строка, хм ...), повернуть его вспять, чтобы получить заголовок статуса в конце (* кашель *), порубить его, отрубить заголовок, взять MD5 из кусков , вычеркните нечисловые символы из хеша, сложите оставшиеся целые числа больших чисел вместе, вставьте 0.переднюю часть, преобразуйте в число с плавающей точкой, готово.

Создает поплавки различной длины на интервале 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

С

Генерация случайных с использованием идентификатора процесса.

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

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

Пример вывода:

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


0

питон

Краткость Python не перестает удивлять. Поскольку использование случайного изображения imgur, по-видимому, недопустимо, я использовал отличный источник случайности: чат 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 испытаний:

3258789746
1899058937
3811869909
274739242
1292809118

Не совсем случайно, но опять же, ни один из них не является.


я думаю, что правило 2 не позволяет URL- whatever.com/random
адресам,

@izabera 2 из других ответов использовали это?
Qwr

Нет, вы явно используете случайно сгенерированный контент. другие ответы просто открывают какую-то неслучайную веб-страницу, чтобы получить начальное число, а затем распечатать случайное число.
Изабера

@izabera Я изменил свой случайный источник. Что вы думаете об этом сейчас?
4:28

теперь все нормально: D
изабера

0

Perl

Я видел много ответов, которые делали HTTP-запросы, которые мне кажутся расточительными, потому что под крышками на проводе передаются случайные числа. Поэтому я решил написать какой-нибудь код для более низкого уровня:

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

Дает случайные порты в диапазоне 0,65535, теоретически. На практике есть несколько портов, которые вы никогда не увидите, поэтому распределение далеко от совершенства. Но это так, AFAICT минимальный объем работы, который вы можете сделать, чтобы получить некоторую энтропию от удаленного хоста, у которого открыт порт.

PS - Обработка ошибок оставлена ​​читателю в качестве упражнения ;-)


0

С

// 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;
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.