Python中不使用模块和时钟的(伪)随机数生成

Python中不使用模块和时钟的(伪)随机数生成,python,random,Python,Random,我正在使用Python进行一个竞赛,我正在创建一个机器人来玩游戏。问题是,它没有安装任何c支持,因此我无法访问random、numpy和scipy模块 我将有大约400mb的内存可用,我正在寻找一种方法来产生0到1之间的统一随机数,以便在游戏期间进行模拟 请注意,我以前使用过时钟时间来生成单个数字,但问题是我需要大量的数字,而时钟变化不大,这将导致始终保持相同的数字。事实上,我被限制在最大1秒,比如说,100k个数字 我正在考虑加载数据,但问题是机器人总是使用相同的数字。同样,我需要使用这些数字

我正在使用Python进行一个竞赛,我正在创建一个机器人来玩游戏。问题是,它没有安装任何c支持,因此我无法访问
random
numpy
scipy
模块

我将有大约400mb的内存可用,我正在寻找一种方法来产生0到1之间的统一随机数,以便在游戏期间进行模拟

请注意,我以前使用过时钟时间来生成单个数字,但问题是我需要大量的数字,而时钟变化不大,这将导致始终保持相同的数字。事实上,我被限制在最大1秒,比如说,100k个数字

我正在考虑加载数据,但问题是机器人总是使用相同的数字。同样,我需要使用这些数字的情况略有不同

使用Python 2.7,希望大家有一些建议。

您可以使用一个实现。我发现,这是模仿维基百科上的伪代码

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Based on the pseudocode in https://en.wikipedia.org/wiki/Mersenne_Twister. Generates uniformly distributed 32-bit integers in the range [0, 232 − 1] with the MT19937 algorithm

Yaşar Arabacı <yasar11732 et gmail nokta com>
"""
# Create a length 624 list to store the state of the generator
MT = [0 for i in xrange(624)]
index = 0

# To get last 32 bits
bitmask_1 = (2 ** 32) - 1

# To get 32. bit
bitmask_2 = 2 ** 31

# To get last 31 bits
bitmask_3 = (2 ** 31) - 1

def initialize_generator(seed):
    "Initialize the generator from a seed"
    global MT
    global bitmask_1
    MT[0] = seed
    for i in xrange(1,624):
        MT[i] = ((1812433253 * MT[i-1]) ^ ((MT[i-1] >> 30) + i)) & bitmask_1


def extract_number():
    """
    Extract a tempered pseudorandom number based on the index-th value,
    calling generate_numbers() every 624 numbers
    """
    global index
    global MT
    if index == 0:
        generate_numbers()
    y = MT[index]
    y ^= y >> 11
    y ^= (y << 7) & 2636928640
    y ^= (y << 15) & 4022730752
    y ^= y >> 18

    index = (index + 1) % 624
    return y

def generate_numbers():
    "Generate an array of 624 untempered numbers"
    global MT
    for i in xrange(624):
        y = (MT[i] & bitmask_2) + (MT[(i + 1 ) % 624] & bitmask_3)
        MT[i] = MT[(i + 397) % 624] ^ (y >> 1)
        if y % 2 != 0:
            MT[i] ^= 2567483615

if __name__ == "__main__":
    from datetime import datetime
    now = datetime.now()
    initialize_generator(now.microsecond)
    for i in xrange(100):
        "Print 100 random numbers as an example"
        print extract_number()
#/usr/bin/env蟒蛇2
#-*-编码:utf-8-*-
"""
基于中的伪码https://en.wikipedia.org/wiki/Mersenne_Twister. 生成[0,232]范围内均匀分布的32位整数− 1] 使用MT19937算法
亚尔·阿拉巴克
"""
#创建长度为624的列表以存储生成器的状态
MT=[0表示X范围内的i(624)]
索引=0
#获取最后32位
位掩码_1=(2**32)-1
#得到32分。一点
位掩码_2=2**31
#获取最后31位
位掩码_3=(2**31)-1
def初始化_生成器(种子):
“从种子初始化生成器”
全球机器翻译
全局位掩码_1
MT[0]=种子
对于X范围内的i(1624):
MT[i]=(1812433253*MT[i-1])^((MT[i-1]>>30)+i))&位掩码
def提取_编号():
"""
基于索引th值提取一个调和伪随机数,
每624个数字调用generate_numbers()
"""
全球指数
全球机器翻译
如果索引==0:
生成_编号()
y=MT[索引]
y^=y>>11
y^=(y 18
索引=(索引+1)%624
返回y
def生成_编号():
“生成一个624个无阻尼数字的数组”
全球机器翻译
对于X范围内的i(624):
y=(MT[i]&位掩码_2)+(MT[(i+1)%624]&位掩码_3)
MT[i]=MT[(i+397)%624]^(y>>1)
如果y%2!=0:
MT[i]^=2567483615
如果名称=“\uuuuu main\uuuuuuuu”:
从日期时间导入日期时间
now=datetime.now()
初始化_生成器(现在为微秒)
对于X范围内的i(100):
“打印100个随机数作为示例”
打印摘录编号()

数学是你最好的答案:

X(n+1)=(aX(n)+c)模m


如果脚本在linux上运行,请尝试使用
/dev/uradom

with open('/dev/urandom', 'rb') as f:
    random_int = reduce(lambda acc, x: (acc << 8) | x, map(ord, f.read(4)), 0)
以open('/dev/uradom',rb')作为f的
:
random_int=reduce(lambda acc,x:(accFWIW),随机模块包含用纯python编写的Wichman Hill生成器类(不需要C):

以下是经过清理的源代码:

class WichmannHill(Random):

    def seed(self, a=None):
        a, x = divmod(a, 30268)
        a, y = divmod(a, 30306)
        a, z = divmod(a, 30322)
        self._seed = int(x)+1, int(y)+1, int(z)+1

    def random(self):
        """Get the next random number in the range [0.0, 1.0)."""
        x, y, z = self._seed
        x = (171 * x) % 30269
        y = (172 * y) % 30307
        z = (170 * z) % 30323
        self._seed = x, y, z
        return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0

真的吗?核心标准库模块
random
不可用?@kroolik我想是的。看看。算法非常简单,如果不是用于加密或高赌注赌博,结果也不错。
uuid
模块呢?@kroolik-
uuid.uuid4()
使用
os.uradom()
如果可用,则使用
随机
模块。虽然这只生成整数,但不从[0..1]浮起。实际上可以生成整数。@delnan-通过将结果数字除以最大值(2^32-1)来轻松修复。如果我理解正确,我不需要更改624值,只需重复调用extract number?不,您不需要。该算法一次只生成624个值;您可以使用需要的数量。624只是它生成新数字的点(通过
生成\u numbers()
).但在选择参数(a、c、m)时要格外小心。即使是仔细的选择也会导致质量低下,而不经深思熟虑的选择也会产生周期非常短的生成器。Wikipedia的文章列出了好的CANIDATE的条件;它还列出了现实世界中实现所使用的值。其中一些很差,但没有一个是灾难性的。@delnan由于资源有限,它是不过,这是最简单的。性能和内存使用与这些问题无关。对于任何状态大小,都有一些参数可以给出一个合适的PRNG,而这些参数只能一次又一次地吐出相同的半个5数字。您希望避免后者,因为它们只会给出质量糟糕的数字,而成本却与您的d选择了更好的参数。@delnan关于这些参数有什么建议吗?你需要知道什么?@PascalvKooten正如我所说,Wikipedia有详细信息(在“周期长度”部分)。这比MT实现快得多。我会看看它是否有效!不幸的是:
OSError:[Errno 2]没有这样的文件或目录:'/dev/urandom'
。因此,我在尝试使用
random
库时遇到的错误是:
OSError:[Errno 2]没有这样的文件或目录:'/dev/urandom'
。这很可能不起作用。
>>> import random
>>> rng = random.WichmannHill(8675309)
>>> rng.random()
0.06246664612856567
>>> rng.random()
0.3049888099198217
class WichmannHill(Random):

    def seed(self, a=None):
        a, x = divmod(a, 30268)
        a, y = divmod(a, 30306)
        a, z = divmod(a, 30322)
        self._seed = int(x)+1, int(y)+1, int(z)+1

    def random(self):
        """Get the next random number in the range [0.0, 1.0)."""
        x, y, z = self._seed
        x = (171 * x) % 30269
        y = (172 * y) % 30307
        z = (170 * z) % 30323
        self._seed = x, y, z
        return (x/30269.0 + y/30307.0 + z/30323.0) % 1.0