2016-06-23 4 views
1

Этот небольшой скрипт генерирует случайный поплавок beween 0 и 1, а затем, если ее меньше, чем «+0,000111111111111» будет выводить сообщение «нашли»Странного поведение питона случайного

import random 

value = 0.4/3600 
print value 

while True: 
    rand = random.random() 

    print "RAND IS: " + str(rand) + "----- VAL IS " + str(value) 
    if rand < value: 
     print "found it" 

Так, казалось бы, скрипт работает и его никогда не «находит это», однако, когда я комментирую инструкцию печати перед оператором if, команда командной строки ЗАПОЛНЯЕТСЯ «найденным», даже если значение rand не меньше значения. Какого черта?

ответ

2

Ваша программа не найти числа, которые меньше и больше «ценности», независимо от того, или не печатает это все из них. Просто вывод, в обе стороны, вас сбивает с толку. Это связано с тем, что: (а) ваш компьютер быстрее, чем вы можете себе представить, пока ему нечего печатать; (b), но когда делает, необходимо распечатать что-то, что замедляется до такой степени, что вы действительно можете увидеть распечатки; (c) количество итераций между успешными «выводами» больше, чем вы могли ожидать.

Чтобы продемонстрировать все вышесказанное, я написал этот сценарий:

#! /usr/bin/python 

import time 
import random 
import csv 
import sys 

def how_long_until(v): 
    n = 0 
    start = time.clock() 
    rng = random.random 
    while True: 
     n += 1 
     if rng() < v: break 
    stop = time.clock() 
    return n, stop - start 

wr = csv.writer(sys.stdout, quoting=csv.QUOTE_MINIMAL) 
wr.writerow(("loops", "cpu.time")) 

value = 0.4/3600 
for _ in range(10000): 
    wr.writerow(how_long_until(value)) 

Это генерирует случайные числа до тех пор, пока не найдет один меньше, чем ваш «значение», а затем выписывает числа итераций цикла и истекшее время CPU, чтобы найти его. Он делает это ДЕСЯТЬ ТЫСЯЧ. На моем компьютере, который старый, но не , что старый, эта программа заняла шесть секунд для запуска.

И затем я построил гистограммы обоих. Во-первых, давайте посмотрим на количество петель:

Histogram of number of loops needed to find a small random number, with inset zoom-in on the range 0...20000

Вы можете увидеть, что, хотя он часто занимает всего несколько тысяч итераций, чтобы найти случайное число меньше, чем 0,4/3600, он может занять многие из 80 000 итераций! Вот почему вам могло показаться, что «найденный» никогда не печатался.

Теперь давайте посмотрим на истекшее время:

Histogram of CPU time in milliseconds needed to find a small random number

Он очень похож на гистограмме количество петель, но обратите внимание на масштаб по оси Х. Это время в миллисекундах. Даже когда требуется 80000 итераций, чтобы найти следующий номер меньше 0,4/3600, для этого нужно только компьютер четыре миллисекунды! Вот почему вам показалось, что «нашел это» было непрерывно печатать, когда вы прокомментировали распечатку с итерацией.

+0

Вау. Как и анализ, может украсть часть писателя.Вы добавили перерыв в свой код, который, как упоминалось выше, был недостающей частью. – Hashman

+0

@ Hashman Это не было (и действительно еще не ясно), ясно ли, что OP _wanted_ сценарий остановился, когда он нашел достаточно маленькое значение. Модуль 'csv' stdlib недооценивается. – zwol

3

Ваш цикл while предназначен для работы навсегда, так как True всегда True. Вы никогда не выходите из этого бесконечного цикла. Даже если он находит значение, он просто печатает его, потому что условие, которое вы даете циклу while, по-прежнему истинно. Так как вы не можете изменить условие, вам нужно добавить заявление перерыв:

while True: 
    rand = random.random() 
    print "RAND IS: " + str(rand) + "----- VAL IS " + str(value) 
    if rand < value: 
     print "found it" 
     break 
+0

Спасибо, я думаю, что сойду с ума – Cherona

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