@Nimachakin

Как повысить эффективность кода? Или такое поведение программы считается нормальным?

Здравствуйте. Продолжаю учиться программированию и попробовал написать программу подсчета вероятности выпадения орла и решки при n-ом количестве бросков. Вот сам код:

import random

# Начальные условия
monetka = ['орел', 'решка']
Орлов = 0
Решек = 0
count = 0
times = 1

# Задание количества бросков
while times:
    try:
        run = int(input('Задайте количество бросков: '))
    except ValueError as err:
        print('Введите целое число')
    else:
        times = run

        # Цикл бросков монеты n раз, где n = times
        while times:
            var = random.choice(monetka)
            if var == 'орел':
                Орлов += 1
                count += 1
                times -= 1
            elif var == 'решка':
                Решек += 1
                count += 1
                times -= 1

        # Вывод текущего результата на экран
        if times == 0:
            print('Текущие результаты данной сессии: бросков монеты - {0}, орлов = {1} (вероятность - {2:%}, '
                  'решек = {3} (вероятность - {4:%}).'.format(count, Орлов, Орлов/count, Решек, Решек/count))

            # Продолжение испытаний или завершение программы
            while not times:
                new_run = input('Продолжить? y/n: ')
                if new_run not in ['y', 'n']:
                    print("'y' или 'n'")
                elif new_run == 'y':
                    times += 1
                    continue
                elif new_run =='n':
                    print('Конечные результаты данной сессии: бросков монеты - {0}, орлов = {1} (вероятность - {2:%}, '
                          'решек = {3} (вероятность - {4:%}).'.format(count, Орлов, Орлов/count, Решек, Решек/count))
                    break


Вопрос вот в чём: при n > 90000 результат выводится не сразу, например, когда я задаю 200000 бросков результат появится не раньше, чем через 1,5-2 секунды. Этот связано с кривым кодом/производительностью моего ПК/всё вместе, или просто программе действительно необходимо столько времени на обработку указанного количества испытаний?
  • Вопрос задан
  • 884 просмотра
Решения вопроса 1
adugin
@adugin Куратор тега Python
Наиболее быстрый алгоритм:
from random import random

while True:
    try:
        total = int(raw_input('\nВведите количество бросков: '))
    except ValueError:
        print 'Введено некорректное значение: ожидается целое число.'
    else:
        # side1 = sum(random() < 0.5 for n in xrange(total))
        side1 = int(round(sum(random() for n in xrange(total))))  # эквивалент random() >= 0.5
        side2 = max(0, total) - side1
        print 'Результат: орёл - {0}, решка - {1}'.format(side1, side2)
    finally:
        if raw_input('\nПопробовать ещё раз (Y)? ').upper() != 'Y':
            break

Ещё вариант:
import collections, random

options = ('орёл', 'решка')

while True:
    stats = collections.Counter(dict.fromkeys(options, 0))
    try:
        stats.update(
            random.choice(options) for test in xrange(
                input('\nВведите количество бросков: ')
            )
        )
    except:
        print 'Введено некорректное значение: ожидается целое число.'
    else:
        print 'Результат: {0} - {{{0}}}, {1} - {{{1}}}'.format(*options).format(**stats)
    finally:
        if raw_input('\nПопробовать ещё раз (Y)? ').upper() != 'Y':
            break

Замеры скорости:
>>> timeit('choice((0,1))', setup='from random import random, choice', number=10**6)
1.4363103769230747
>>> timeit('random() < 0.5', setup='from random import random, choice', number=10**6)
0.18878976080804932

0) Вас не смущает, что Вы используете заведомо равномерное (uniform) распределение, о котором говорится во вступительном абзаце к модулю random?
1) Про русский язык уже написали. Кроме того, зачем смешивать английские слова (times) с транслитом (monetka)? Пишите всё на английском.
2) input() уже конвертирует значение из строки. Если число нецелое (float), то int() отработает без ошибок: int(3.14) = 3
3) Странная структура программы. Не надо делать вложенную структуру (почему цикл бросков монеты идёт под else?), используйте break и continue, чтобы код был более плоским. "Плоское лучше, чем вложенное".
4) В цикле броско монеты операторы "count += 1" и "times -= 1" следует вынести из блока if..elif, чтобы не дублировать оди и тот же код, который всё равно должен выполниться.
5) Если не выпал орёл, то проверять условие var == 'решка' не нужно, достаточно простого else. Там кроме решки больше ничего быть не может.
6) Какая версия Python? 2.x или 3.x? Про целочисленное деление помните?
7) Дальше у меня сломался моск...
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
bobrovskyserg
@bobrovskyserg
1. Это поведение - норма.
Попробуй заменить
var = random.choice(monetka)
на
var = 'орел'
и ты увидишь, на что уходит время.

2. Код не выглядит профессионально, но поскольку "продолжаю учиться программированию", забей на выливающийся тут неадекват.

Удачи.

UPDATE
import random

coin = ('head', 'tail') 
heads = tails = count = 0

while True:
    while True:
        try:
            times = int(input('Amount of coin toss?: '))
            break
        except ValueError:
            print('Must be integer')

    for i in range(times):  # +скорость +однозначность
        var = random.choice(coin)
        count += 1
        if var == 'head':  # +наглядность +скорость
            heads += 1
        else:
            tails += 1

    print('Current results: head count = {0} ({1:%}), tail count = '
          '{2} ({3:%})'.format(heads, heads / count, tails, tails / count))

    while True:
        new = input('Continue? y/n: ')
        if new in ('y', 'n'):
            break
        else:
            print('Print "y" or "n"')

    if new == 'n':
        break

print('Final results: head count = {0} ({1:%}), tail count = '
      '{2} ({3:%})'.format(heads, heads / count, tails, tails / count))
Ответ написан
Комментировать
Собрались тут элитарии и гопники, и те и другие набросились на человека... Фиг он ещё чего спрашивать будет. А он же старался, писал чего-то. Что - само по себе - похвально. Рефакторинг полезен, чтоб перейти от плохой программы к хорошей программе и по ходу дела понять, чем хорошая программа лучше плохой.

Для начала.

- Русские названия переменных не годятся. Русские слова, написанные транслитом, как названия не годятся тоже. Только английские слова.
- Если вас заботит скорость, - зачем вы делаете сначала random.choice, а потом сравниваете результат (строку) с другой строкой? Используйте random.randint(0, 1), который выдаст вам одно из двух чисел; если нуль - орёл, единица - решка.
Ответ написан
Hateman31
@Hateman31
Делиться мыслями - это круто!
Выбрасывай в мусорку всё. Сразу.
Это не рефакторить надо, а переписывать заново.
Ответ написан
Комментировать
@Nimachakin Автор вопроса
Всем спасибо за советы. Я попробовал переписать программу, следуя вашем рекомендациям и положениям pep8. Структура у меня изменилась, программа работает исправно:
import random

coin = ('head', 'tail')    # Initial data
heads = 0
tails = 0
count = 0
times = 1

while times:    # Define the amount of coin toss
    try:
        ch = int(input('Amount of coin toss?: '))
    except ValueError as err:
        print('Must be integer')
        continue
    else:
        times = ch

    while times:    # Loop for coin toss for n times, where n = ch
        var = random.choice(coin)
        count += 1
        times -= 1
        if var == coin[0]:
            heads += 1
        else:
            tails += 1
        if not times:
            print('Current results: head count = {0} ({1:%}), tail count = '
                  '{2} ({3:%})'.format(heads, heads/count, tails, tails/count))

    while not times:    # Option for continuation or conclusion
        new = input('Continue? y/n: ')
        if new not in ('y', 'n'):
            print('Print "y" or "no"')
        elif new == 'y':
            times = 1
            continue
        else:
            print('Final results: head count = {0} ({1:%}), tail count = '
                  '{2} ({3:%})'.format(heads, heads/count, tails, tails/count))
            break

Пока не претендую на профессиональный код, просто интересно, где я снова наступаю на грабли?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы