没有时间基准的随机[关闭]


9

计算机不会无处不在地创建随机数,因为时间很可能是随机性的普遍基础。

我希望您创建一个使用以下规则创建随机数的代码:

  • 在程序的任何时候都不允许以时间为基础。
  • 不允许使用预定义的随机/伪随机函数。
  • 生成的数字可以在任何范围内。那么至少两个不同的整数:D
  • 数字回显。

2
您不清楚“生成的数字可以在任何范围内”是什么意思。您是说编码人员可以自由选择范围吗?还是他们必须支持用户要求的任何范围?这两个都是有问题的。如果用户请求一个范围,那么如果他们请求的数字超出了内置数据类型的范围,该怎么办?如果编码人员可以自由选择,我会选择1到1之间的整数。:D
Jonathan Van Matre 2014年

2
应该是一个代码高尔夫……
Mukul Kumar 2014年

我以人气问题开始这个问题,代码高尔夫球会更适合这个问题吗?
丹丹2014年

@Daniel是的,但让这个问题成为受欢迎程度问题,并用有趣的新规则发布带有代码高尔夫球的新问题(随机生成)
Mukul Kumar 2014年

1
用互联网作为种子似乎是欺骗吗?
Dean MacGregor 2014年

Answers:


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

我用JS编写了Mersenne Twister。然后,我意识到我必须从某个地方获得种子。

因此,我决定从Stack Exchange API中获取它!(我可以使用localStorage并增加一个计数器,但这没什么好玩的。)因此,我获取了10个最近有效的答案,然后我只将响应中每4个或更少的连续数字加起来。

这些种子总是不同的,因为Stack Overflow不断更新(并且我的配额不断减少!),这些数字包括答案ID,问题ID,分数,上/下投票数,所有者代表/ ID和包装器数据(配额等)。 )。在一次运行中,我得到了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的有效性:

我对“ 近似钟形曲线”的回答中,我使用的数据生成取决于良好的精度。让我们以此作为rng来运行它。输出:

在此处输入图片说明

正如我所预料的那样。这真是太糟糕了。


5

C

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

我不确定这是否符合“不允许的时间”标准,因为它基本上是通过故意忽略线程安全性而将调度程序用作熵的来源。它通过使用基本的伪随机函数(Lehmer随机数生成器)和硬编码的初始种子来工作。然后,它将启动20个线程,这些线程全部使用一组共享变量运行Lehmer计算。

似乎运行良好,这是几个连续的运行:

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发布钟形曲线中获得一些启发后,我将12MB的随机性转储到文件中,并将其上传到CAcert。它在所有顽固测试中均未通过,但在ENT测试中获得了可观的7.999573(总分8 )(仅潜在确定性)。奇怪的是,将线程数加倍会使情况变得更糟。


4

C

通过使用从https://stackoverflow.com/questions获取种子,它生成0-255范围内的随机数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个非常接近,在所有3个示例中重复相同的模式。与随机数发生器的预期输出不完全相同。
izabera 2014年

@izabera当涉及到生成随机数的指针时……一切都取决于您的计算机(RAM和处理器),也许当前正在使用“ new int”馈入“ ptr”的地址!您试图运行此代码?
Mukul Kumar 2014年

让我添加一些更改
Mukul Kumar 2014年

我现在尝试了一下,在我的机器上似乎总是能得到类似的信息11230576, 0, 11206992, 0, 2053725299,但对我而言,这似乎并不是随机的。
izabera 2014年


2

佩尔

通过互联网获取种子会带来什么垃圾?听起来像是对我作弊;-)我更喜欢将种子提供给加密哈希函数,并提供介于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”调整为您喜欢的字符串即可。或者如果您是极简主义者,则将其完全忽略掉=)


我猜想,在标准库中值得其名称的任何加密函数都在内部使用加密安全的RNG。
duci9y

对此我不确定。Digest :: MD5 / Digest :: SHA1产生完全确定的,可重复的输出,那么它需要一个随机数做什么呢?
skibrianski 2014年

抱歉! 我只是飞过您的答案,以为您在生成密钥而不是摘要。
duci9y 2014年

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 MB的文件(由10 7 组成short),并将其提交给CACert。这是结果的屏幕截图(已对其进行了编辑以使其看起来不错,但数字保持不变):

结果

我对结果感到惊讶,因为它在Entropy测试中的时钟为7.999991,并通过了所有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

重击范围:0到1之间的整数

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

所以你的意思是它只选择0或1?

是的 应该满足“生成的数字可以在任何范围内。那么至少两个不同的整数:D”,不是吗?
Keba 2014年

大概吧。您认为您可以将其扩展到更大的范围吗?

只是echo -n & echo $!会做,但会成为非常糟糕的RNG。您还可以将2更改为任何其他数字,但是数字越大,“随机性”越差。
Keba 2014年

我知道了。感谢您的解释。

1

红宝石

不幸的是,仅Mac。我们用来sox从麦克风中提取字节(作为字符串,ahem ...),将其反转以获取末尾的状态标头(*咳嗽*),将其切碎,切下标头,获取块的MD5 ,从哈希中剔除非数字字符,将剩余的较大整数加在一起,0.在前面贴上a ,转换为浮点数,完成操作。

在区间上生成长度可变的浮点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

使用进程ID随机生成。

#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不允许这样的网址whatever.com/random
izabera 2014年

@izabera 2的其他答案用了吗?
qwr 2014年

是的,您明确地使用了随机生成的内容。其他答案只是访问一些非随机网页以获得种子,然后打印一个随机数。
izabera 2014年

@izabera我已经更改了随机来源。您现在怎么看?
qwr 2014年

现在很好:D
izabera 2014年

0

佩尔

我看到了很多发出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

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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.