2015-02-24 4 views
0

Мне нужно написать функцию -Python Случайных функций без использования случайного модуля

random_number(minimum,maximum) 

без использования случайного модуля, и я сделал это:

import time 

def random_number(minimum,maximum): 
    now = str(time.clock()) 
    rnd = float(now[::-1][:3:])/1000 
    return minimum + rnd*(maximum-minimum) 

Я не уверен, что это хорошо .. есть ли известный способ сделать это со временем?

+0

Можете ли вы уточнить, что ваши требования находятся? Какие тесты случайности нужно пройти? Как написано, трудно понять, о чем вы спрашиваете. – BlackVegetable

+0

Определите, что вы подразумеваете под случайным, для некоторых стандартных модульных «rand» недостаточно, а для некоторого 'return 4; // на основе справедливого броска кубика. – luk32

+0

Попытка изображения этой функции должна быть как randrange, это достаточно хорошо? – oridm

ответ

2

Дело в том, что мне нужно сделать что-то, что каким-то образом использует время

Вы могли бы генерировать хаотичность на основе clock drift:

import struct 
import time 

def lastbit(f): 
    return struct.pack('!f', f)[-1] & 1 

def getrandbits(k): 
    "Return k random bits using a relative drift of two clocks." 
    # assume time.sleep() and time.clock() use different clocks 
    # though it might work even if they use the same clock 
    #XXX it does not produce "good" random bits, see below for details 
    result = 0 
    for _ in range(k): 
     time.sleep(0) 
     result <<= 1 
     result |= lastbit(time.clock()) 
    return result 

После того как вы getrandbits(k), это для получения случайного целого в диапазоне [a, b], включая обе конечные точки. Based on CPython Lib/random.py:

def randint(a, b): 
    "Return random integer in range [a, b], including both end points." 
    return a + randbelow(b - a + 1) 

def randbelow(n): 
    "Return a random int in the range [0,n). Raises ValueError if n<=0." 
    # from Lib/random.py 
    if n <= 0: 
     raise ValueError 
    k = n.bit_length() # don't use (n-1) here because n can be 1 
    r = getrandbits(k)   # 0 <= r < 2**k 
    while r >= n: # avoid skew 
     r = getrandbits(k) 
    return r 

Пример, чтобы генерировать 20 случайных чисел от 10 до 110 в том числе:

print(*[randint(10, 110) for _ in range(20)]) 

Выход:

11 76 66 58 107 102 73 81 16 58 43 107 108 98 17 58 18 107 107 77 

, если getrandbits(k) возвращает k случайные биты, то randint(a, b) должен работать как (без перекоса по модулю и т. д.).

Чтобы проверить качество getrandbits(k), может быть использована утилита dieharder:

$ python3 random-from-time.py | dieharder -a -g 200 

, где random-from-time.py генерирует бесконечный (случайный) двоичный поток:

#!/usr/bin/env python3 

def write_random_binary_stream(write): 
    while True: 
     write(getrandbits(32).to_bytes(4, 'big')) 

if __name__ == "__main__": 
    import sys 
    write_random_binary_stream(sys.stdout.buffer.write) 

, где getrandbits(k) определен выше.


выше предполагает, что вы не можете использовать os.urandom() или ssl.RAND_bytes(), или какой-либо известный PRNG алгоритм, такой как Mersenne Twister реализовать getrandbits(k).


getrandbits(n) реализован с использованием "time.sleep() + time.clock()" терпит неудачу dieharder испытания (слишком много, чтобы быть совпадением).

Идея по-прежнему звучит: дрейф часов может использоваться как источник случайности (энтропия), но вы не можете использовать его напрямую (распределение неравномерно и/или некоторые биты зависят); биты могут быть переданы как семя в PRNG, который вместо этого принимает произвольный источник энтропии. См. "Mixing" section.

1

Разрешено ли вам читать случайные данные в каком-либо специальном файле? В Linux файл `/ dev/urandom 'обеспечивает удобный способ получения случайных байтов. Вы можете написать:

import struct 
f = open("/dev/urandom","r") 
n = struct.unpack("i",f.read(4))[0] 

Но это не будет работать под Windows.

+0

Дело в том, что мне нужно что-то делать, чтобы каким-то образом использовать время – oridm

+0

use 'os.urandom()' это тоже работает на Windows. – jfs

0

Использовать API? если разрешено.

import urllib2 

def get_random(x,y): 
    url = 'http://www.random.org/integers/?num=1&min=[min]&max=[max]&col=1&base=10&format=plain&rnd=new' 
    url = url.replace("[min]", str(x)) 
    url = url.replace("[max]", str(y)) 
    response = urllib2.urlopen(url) 
    num = response.read() 
    return num.strip() 

print get_random(1,1000) 
+0

могут быть локальные источники, если разрешены такие, как 'os.urandom()', 'ssl.RAND_bytes()'. Вы можете использовать строковое форматирование '' min = {min} & max = {max} '. Format (min = x, max = y) 'или' urllib.urlencode() 'в более сложных случаях вместо' str.replace() здесь. – jfs

0

Идея получить число от 0 до 1 с помощью модуля времени и использовать, чтобы получить число в range.Following напечатает 20 номеров случайным образом в диапазоне 20 и 60

from time import time 

def time_random(): 
return time() - float(str(time()).split('.')[0]) 

def gen_random_range(min, max): 
return int(time_random() * (max - min) + min) 

if __name__ == '__main__': 
for i in range(20): 
    print gen_random_range(20,60) 
+0

есть как минимум две проблемы: (1) 'time_random()' пытается вернуть текущие доли секунды, которые являются очень регулярными (2) 'gen_random_range()', могут приводить к неправильным результатам, даже если 'time_random()' работают (создание равномерно распределенных '[0,1.)' чисел с плавающей запятой), например, см. [эта ошибка Python] (https://bugs.python.org/issue24567) – jfs

Смежные вопросы