# Подсчитать, сколько было выделено памяти под переменные в ранее разработанных программах в рамках первых трех уроков.
# Проанализировать результат и определить программы с наиболее эффективным использованием памяти.
# Примечание: Для анализа возьмите любые 1-3 ваших программы или несколько вариантов кода для одной и той же задачи.
# Результаты анализа вставьте в виде комментариев к коду.
# Также укажите в комментариях версию Python и разрядность вашей ОС.


# Задача: Найти сумму n элементов следующего ряда чисел: 1 -0.5 0.25 -0.125...
import sys


# Решение №1. Динамическое программирование
def solution1(n):
    def recursive(elem, deep):
        if deep == 1:
            return elem, sys.getsizeof(elem) + sys.getsizeof(deep)
        else:
            deep_elem, deep_size = recursive(elem * -0.5, deep - 1)
            return elem + deep_elem, sys.getsizeof(elem) + sys.getsizeof(deep) + deep_size
    return recursive(1, n)


# Решение №2. Сумма ряда
def solution2(n):
    lst = [1]
    for _ in range(1, n):
        lst.append(lst[-1] / -2)
    return sum(lst), sys.getsizeof(lst) + sys.getsizeof(range(1, n)) + sum([sys.getsizeof(e) for e in lst])


# Решение №3. Перебор элементов с аккумулятором
def solution3(n):
    summ = 0
    elem = 1
    for _ in range(n):
        summ += elem
        elem /= -2
    return summ, sys.getsizeof(summ) + sys.getsizeof(elem) + sys.getsizeof(range(n))


# Решение №4. Геометрическая прогрессия
def solution4(n):
    summ = 1 * (1 - (-0.5) ** n) / (1 - (-0.5))
    return summ, sys.getsizeof(summ)


if __name__ == '__main__':
    for i in [1, 2, 3, 4]:
        print(f'===Решение {i}===')
        n = 8
        summ, size = locals()[f'solution{i}'](n)
        print(f'Ответ для n={n}: ', summ)
        print('Количество используемой памяти: ', size)

# Результат:
# ===Решение 1===
# Ответ для n=8:  0.6640625
# Количество используемой памяти:  420
# ===Решение 2===
# Ответ для n=8:  0.6640625
# Количество используемой памяти:  380
# ===Решение 3===
# Ответ для n=8:  0.6640625
# Количество используемой памяти:  96
# ===Решение 4===
# Ответ для n=8:  0.6640625
# Количество используемой памяти:  24
#
# Выводы:
# Python 3.7, 64bit
# В решении 1 используется рекурсивная функция и переменные создаются на каждом уровне стека.
# В решении 2 мы храним все промежуточные результаты в списке. Размер используемой памяти получился меньше, чем в
# решении 1 за счет того, что в решении 1 мы на каждом уровне стека храним не только текущий элемент elem, но и его
# порядковый номер deep.
# В решении 3 мы аллоцируем память для переменной суммы, текущего элемента и объекта range()
# В решении 4 мы сразу получаем результат, поэтому нам достаточно выделить только под ответ
