Ниже приведен набор незначительных модификаций первоначально предоставленного кода, который будет правильно вычислять оценку.
Я пометил модификации с комментариями с префиксом ####
и пронумеровал их со ссылкой на пояснения, которые следуют ниже. .
import random
#variable declaration
numberOfStreaks = 0
for experimentNumber in range(10000):
# Code that creates a list of 100 'heads' or 'tails' values.
CoinFlip = [] #### (1) create a new, empty list for this list of 100
for i in range(100):
CoinFlip.append(random.randint(0,1))
#does not matter if it is 0 or 1, H or T, peas or lentils. I am going to check if there is multiple 0 or 1 in a row
#### # (6) example / test
#### # if uncommented should be 100%
#### CoinFlip = [ 'H', 'H', 'H', 'H', 'H', 'H', 'T', 'T', 'T', 'T', 'T', 'T' ]
# Code that checks if there is a streak of 6 heads or tails in a row.
streak = 1 #### (2, 4) any flip is a streak of (at least) 1; reset for next check
for i in range(1, len(CoinFlip)): #### (3) start at the second flip, as we will look back 1
if CoinFlip[i] == CoinFlip[i-1]: #checks if current list item is the same as before
streak += 1
else:
streak = 1 #### (2) any flip is a streak of (at least) 1
if streak == 6:
numberOfStreaks += 1
break #### (5) we've found a streak in this CoinFlip list, skip to next experiment
#### if we don't, we get percentages above 100, e.g. the example / test above
#### this makes some sense, but is likely not what the book's author intends
print('Chance of streak: %s%%' % (numberOfStreaks / 100.0))
Объяснение этих изменений
Ниже приводится краткое объяснение этих изменений. Каждый из них в значительной степени независим, исправляя различные проблемы с кодом.
- очистка / создание списка CoinFlip в начале каждого эксперимента
- без этого новые элементы добавил в список из предыдущего эксперимента
- подтверждение того, что любой переворот, даже один
'H'
или 'T'
(или 1
или 0
), представляет полосу 1 - без этого изменения, код фактически требует шести последовательных совпадений с первоначальным броском монеты, в общей сложности семь (немного менее интуитивное альтернативное изменение будет заменой
if streak == 6:
на if streak == 5:
)
- начиная проверку со второго броска, используя
range(1, len(CoinFlip))
(списки nb нумерованы нулями) - , когда код просматривает список ,
for
l oop с range()
, начинающимся с 0, будет некорректно сравнивать индекс 0
с индексом -1
( последний элемент списка )
- (перемещение прицела и) сброс Счетчик
streak
перед каждой проверкой - без этого изменения начальная полоса в эксперименте может быть добавлена к частичной полосе из предыдущего эксперимента (см. Проверка кода для предлагаемой демонстрации)
- при выходе из чека, как только мы обнаружили полосу
Этот вопрос в книге несколько плохо определен, и заключительная часть может быть истолкована как означающая "проверьте, если [хотя бы?] a [холост?] найдена полоса [точно?] шесть [или больше?] найдено ". Это решение интерпретирует check как булеву оценку (т. Е. Мы только фиксируем, что этот список содержал полосу или нет), и интерпретирует a не исключительно (т.е. мы допускаем более длинные полосы) или несколько полос для подсчета; как было верно в коде, представленном в вопросе).
(Необязательно 6.) Тестирование кода
Пример с комментариями / «Тест» позволяет переключать обычно генерируемые случайным образом сальто на одно и то же известное значение в каждом эксперименте. В этом случае фиксированный список, который должен рассчитываться как 100%. Если вы не согласны с интерпретацией спецификации задачи и отключите выход проверки, описанной в (5.), вы можете ожидать, что программа выдаст 200%, поскольку в каждом эксперименте есть две четкие полосы по шесть. Отключение break
в сочетании с этим вводом сообщает точно, что.
Вы должны всегда использовать этот тип техники (использовать известный ввод, проверять вывод), чтобы убедить себя, что код работает или не работает так, как он утверждает или как вы ожидаете.
Фиксированный ввод CoinFlip = [ 'H', 'H', 'H', 'H', 'T', 'T', 'T' ]
может быть использован для выделения проблемы, решаемой с помощью (4.). В случае возврата код вычислит процент экспериментов (все с этим вводом), содержащих полосу из шести последовательных H
или T
как 50%. Хотя (5.) устраняет независимую проблему, удаление добавленного break
еще больше усугубляет ошибку и повышает рассчитанный процент до 99,99%. Для этого ввода рассчитанный процент, содержащий полосу шести, должен составлять 0%.
Вы найдете полный код, как показано здесь, дает оценки около 80%. Это может быть удивительно, но автор книги намекает, что это может иметь место:
Человек почти никогда не запишет полосу из шести голов или шести хвостов в подряд, хотя вполне вероятно, что это произойдет при действительно случайных бросках монет.
- Аль Свейгарт, Полосы с перевернутыми монетами
Можно также рассмотреть дополнительные источники. WolframAlpha рассчитывает, что шанс получить "полосу из 6 голов за 100 подбрасываний монет" составляет примерно 1 за 2 . Здесь мы оцениваем вероятность получения полосы из 6 ( или более ) голов или полосы из шести ( или более ) хвостов, что можно ожидать быть еще более вероятным. В качестве более простого, независимого примера этого кумулятивного эффекта: предположим, что вероятность забрать сердце из обычной колоды игральных карт составляет 13 из 52, а взять сердце или алмаз - 26 из 52.
Примечания к расчету
Может также помочь понять, что автор также использует ярлык для вычисления процента. Это может сбить с толку новичков, смотрящих на окончательный расчет.
Напомним, рассчитывается процент:
Мы знаем, что всего количество экспериментов, которые нужно запустить, будет 10000
Поэтому
Постскриптум: Я позволил себе сменить 100
на 100.0
в последней строке. Это позволяет коду правильно рассчитать процент в Python 2. Это не требуется для Python 3, как указано в вопросе и книге.