Зачем математика разработчику

Рассмотрим простой пример: ‘Найти сумму чисел в некотором диапазоне от нуля’. Сделать это можно различными способами. Представим наиболее очевидные способы решения на Python (v.3.8.x) и полученное для них время (через timeit).
Первым способом решения может быть использование built-in функций sum и range:

from timeit import timeit

def get_sum_of_range(n=100_000_000):
    return sum(range(n))

print(timeit.timeit(get_sum_of_range, number=1))
# -> 0.5181200389997684

Получаем время в 0.518 мс.
Другой способ – использование numpy:

from numpy import sum as np_sum, arange as np_arange

def get_sum_of_range_with_numpy(n=100_000_000):
    return np_sum(np_arange(n))

print(timeit(get_sum_of_range_with_numpy, number=1))
# -> 0.15053598200029228

Теперь мы получили некоторый рост производительности – время 0.15 мс.

Однако, наиболее быстрый способ представляет использованием простой формулы (n*(n-1))/2 из математики (в формуле используем целочисленное деление при помощи //):

def get_sum_of_range_with_math(n=100_000_000):
    return n * (n - 1) // 2

print(timeit(get_sum_of_range_with_math, number=1))
# -> 1.977000465558376e-06

И теперь результат в 1.977*10-6 или 0.000001977 мс. Получаем значительный рост производительности при использовании мат. формулы. Естественно, что каждый из способов может нести свои недостатки в плане точности в рамках той или иной задачи.
Весь код для сравнения способов:

from timeit import timeit
from numpy import sum as np_sum, arange as np_arange


def get_sum_of_range(n=100_000_000):
    return sum(range(n))


def get_sum_of_range_with_numpy(n=100_000_000):
    return np_sum(np_arange(n))


def get_sum_of_range_with_math(n=100_000_000):
    return n * (n - 1) // 2


print(timeit(get_sum_of_range, number=1))
print(timeit(get_sum_of_range_with_numpy, number=1))
print(timeit(get_sum_of_range_with_math, number=1))

# проверим, что все результаты совпадают
assert get_sum_of_range() == get_sum_of_range_with_numpy() == get_sum_of_range_with_math()
assert get_sum_of_range(42) == get_sum_of_range_with_numpy(42) == get_sum_of_range_with_math(42)
assert get_sum_of_range(357_357) == get_sum_of_range_with_numpy(357_357) == get_sum_of_range_with_math(357_357)

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

Комментарии не должны дублировать информацию, которую можно получить непосредственно из кода, они должны давать дополнительные сведения. Например, если мы обращаемся к API, то в комментарии может быть информация об ограничениях на отправляемые в параметрах запроса данные и т.п. Однако нет смысла писать в комментарии “делаем GET-запрос к …”, ведь мы итак это укажем в самом коде, например, при вызове requests.request("GET", ...).

Здесь мы не рассматриваем разработку аналитического ПО, так как в подобных случаях математика используется сплошь и рядом (вычисление среднего, медианы, среднего взвешенного и т.п.), а вопрос “зачем она нужна” отпадает изначально.

0

Автор публикации

не в сети 4 недели

art610

1000K
Lnovus Support
Комментарии: 0Публикации: 38Регистрация: 04-06-2022
Оцените материал
( Пока оценок нет )
Locus Novus
Добавить комментарий

Авторизация
*
*
Регистрация
*
*
*
Пароль не введен
Генерация пароля