В этом листке мы будем изучать асимптотику факториалов и чисел Cnk, строить графики в библиотеке matplotlib, а также рисовать фракталы черепашкой.
Библиотека matplotlib предназначена для построения практически сколь угодно сложных графиков и диаграмм.
Про неё шутят, что простые вещи в ней делать просто, а сложные — ... теоретически возможно.
Для установки библиотеки нужно запустить следующую программу:
Если в результате её запуска вывод будет примерно такой как ниже, то у вас успех!
C:\some\path\Python38\python.exe -m pip install matplotlib --upgrade --user
Collecting matplotlib
... что-то про downloading или Using cached
... что-то ещё collecting
Installing collected packages: matplotlib, что-то ещё
Successfully installed что-то matplotlib-3.3.1 что-то ещё
Вот типичный простой пример программы, которая строит простой график:
import matplotlib.pyplot as plt
# Создаём картинку fig, а на ней создаём один холст (координатные оси) ax для графиков
fig, ax = plt.subplots()
xx = [0, 1, 2, 3, 4] # Создаём массив x-координат
yy = [5, -3, 0, 1, 4] # Создаём массив y-координат
ax.plot(xx, yy) # Добавляем графики
plt.show() # Выводим на экран
Разберём этот пример подробно.
import matplotlib.pyplot as plt — это де-факто общепринятый стандарт по импортированию этой библиотеки.
fig, ax = plt.subplots() — мы создаём картинку (figure) и на ней одну ось координат (axes).
Теоретически мы можем одновременно работать с несколькими картинками, на каждой из которых будет по несколько разных осей координат.
Обычно с переменной fig не требуется ничего делать, и всё рисование производится в ax.
xx = [0, 1, 2, 3, 4]; yy = [5, -3, 0, 1, 4] — здесь мы создаём списки x- и y-координат графика.
Важно, что количество точек в этих списках должно быть одинаковым.
ax.plot(xx, yy) — здесь мы добавляем в координатную сетку ax график.
Можно добавлять сразу несколько графиков, вызывая ax.plot несколько раз.
plt.show() — запуск окна, в котором отображается наша картина.
Напишите функцию linspace,
принимающую на вход действительные числа x, y и натуральное число n,
и возвращающую список с арифметической прогрессией a1,a2,…,an, в которой a1=x и an=y.
Этой функций удобно пользоваться для построение графиков функций.
Нужно сдать только тело функции. В конец программы будет добавлено:
x, y, n = input().split()
print(*linspace(float(x), float(y), int(n)))
Предположим, что функцию linspace из первой задачи вы уже написали.
Тогда рисовать графики можно так:
import matplotlib.pyplot as plt
from math import sin, cos, sqrt
deflinspace(x, y, n):
...
return [... for i in range(n+1)]
fig, ax = plt.subplots()
xx = linspace(-5, 5, 101)
yy1 = [1/6 * x ** 2 - 2for x in xx]
yy2 = [2*cos(x*2) + 1/4*cos(10*x) for x in xx]
yy3 = [sqrt(abs(x)) for x in xx]
ax.plot(xx, yy1)
ax.plot(xx, yy2)
ax.plot(xx, yy3)
plt.show()
На вход даются числа a,b,c.
На отрезке [−5,5] постройте четыре параболы по 101 точкам:
y=ax2+bx+c,
y=(a+0.1)x2+bx+c,
y=ax2+(b+0.1)x+c,
y=ax2+bx+(c+0.1).
Не меняйте никаких автоматических параметров графика.
Используйте функцию linspace из предыдущей задачи.
Проведите серию экспериментов.
В комментариях ответьте на вопрос: при каких условиях изменение одного из коэффициентов на 0.1 значительно влияют на график параболы и её корни.
Проведите серию экспериментов.
В комментариях ответьте на вопрос: как будет устроен прогресс двух людей за год,
один из которых каждый день прогрессирует на 1%, а другой — регрессирует на 1%.
На вход даётся число n.
Постройте графики количества двоичных цифр в числах:
12,22,…,n2;
13,23,…,n3;
14,24,…,n4;
Количество двоичных цифр можно получить при помощи метода .bit_length().
Не меняйте никаких автоматических параметров графика.
В этой задаче все значения x целые, поэтому функция linspace не требуется.
Используйте просто подходящий range.
Проведите серию экспериментов.
В комментариях ответьте на вопрос: как число двоичных цифр изменяется с ростом n и с ростом показателя степени, в которую n возводится?
На вход даётся число n.
Постройте графики количества двоичных цифр в числах:
21,22,…,2n;
31,32,…,3n;
41,42,…,4n;
В этой задаче все значения x целые, поэтому функция linspace не требуется.
Используйте просто подходящий range.
Проведите серию экспериментов.
В комментариях ответьте на вопрос: как число двоичных цифр изменяется с ростом n и с ростом основания степени?
Сравните показательные и степенные функции. Охарактеризуйте их рост.
На вход даётся число n.
Постройте графики количества двоичных цифр в числах:
12,22,…,n2;
21,22,…,2n;
1!,2!,…,n!;
11,22,…,nn;
Для вычисления факториала используйте функцию factorial из модуля math.
Проведите серию экспериментов.
В комментариях упорядочьте функции n2, 2n, n! и nn по возрастанию и охарактеризуйте разницу в их росте.
Рост каких функций «похож» друг на друга при очень больших n (порядка 2000)?
Во сколько раз примерно отличается количество двоичных цифр в 1000! и в 22000?
Попробуйте заменить число 2 в показателе и основании степени на другие: 0.5, 0.9, 1.001, 2, 3. Как меняются функции?
Для сравнения нарисуйте их все вместе, подписывая графики. Для этого нужно добавлять параметр label (ax.plot(..., label='2**n'),
а перед выводом графика добавить команду ax.legend().
На вход даётся число n.
Постройте графики количества двоичных цифр в числах:
(31)1,(32)2,…,(3n)n;
1!,2!,…,n!;
(21)1,(22)2,…,(2n)n;
Используйте целочисленное деление.
Проведите серию экспериментов.
Попробуйте подобрать такие числа α и β так, чтобы «зазор» между графиками функций был как можно меньше и при больших n выполнялось неравенство:
(αn)n<n!<(βn)n.
На вход даётся число n.
Постройте графики следущих последовательностей:
Cn−10,Cn−11,…,Cn−1n−1;
Cn0,Cn1,…,Cnn;
Cn+10,Cn+11,…,Cn+1n+1;
Проведите серию экспериментов.
В комментариях ответьте на вопрос: какое из чисел Cnk при фиксированном n самое большое. Почему?
Как выглядят графики при достаточно больших n?
На вход даётся число n.
Постройте графики количества двоичных цифр в следущих последовательностях:
Cn−10,Cn−11,…,Cn−1n−1;
Cn0,Cn1,…,Cnn;
Cn+10,Cn+11,…,Cn+1n+1;
Проведите серию экспериментов.
В комментариях ответьте на вопрос: что напоминают графики при больших n?
Насколько они отличаются друг от друга?
На вход даётся число n.
Постройте графики количества двоичных цифр в следущих последовательностях:
C1[1/4],C2[2/4],…,Cn[n/4];
C1[1/3],C2[2/3],…,Cn[n/3];
C1[1/2],C2[2/2],…,Cn[n/2];
Какой функцией можно неплохо приблизить Cn[n/2] при достаточно большом n?
Проведите серию экспериментов.
В комментариях ответьте на вопрос: как устроен рост чисел Cn[αn] с ростом n при фиксированном α?
Попробуйте как можно точнее определить асимптотику Cn[n/2].
В этой задаче мы попытаемся точно установить асимптотику факториала.
Мы уже видели, как устроен рост степенной и показательной функций, факториала и функции nn.
Попробуем собрать факториал из этих «кирпичиков».
А именно представим n! так:
n!≈C⋅nγ⋅αn⋅nn.
То есть в виде произведения константы, степенной функции, показательной функции и nn.
Для определения констант C,γ,α нам пригодится функция,
которая вычисляет отношение факториала к нашей функции.
Напишите функцию f_ratio(n, C, ga, al), которая вычисляет число
C⋅nγ⋅αn⋅nnn!.
Ответ будет проверяться с относительной точностью 10−8.
Эта задача содержит в себе пачку нюансов, поэтому после неудачных экспериментов используйте подсказку.
10
1.0 0.0 0.5
0.37158912
10
1.0 0.0 0.333
21.643161384219646
10
1.0 1.0 0.333
2.1643161384219645
1000
1.0 1.0 0.333
1.4468073814356045e+42
3000
1.0 1.0 0.333
2.7822435344132216e+128
Подсказка
Всё ноль да ноль...
В произведении очень много и маленьких, и больших множителей.
Если сначала слишком долго перемножать маленькие множители, то получится 0, и вся информация потеряется.
Поэтому распишем ответ в виде
C⋅nγ1⋅αn1⋅αn2⋅…⋅αnn−1⋅αnn.
Распределим множители в два списка: список чисел, больших 1, и список чисел, меньших 1.
Дальше пока оба списка не пусты, будем брать множитель, больший 1, если текущее произведение меньше 1, и наоборот.
Проведите серию экспериментов.
Сначала подберите такие числа α1 и α2, что ∣α1−α2∣≤0.01, и
0<f_ratio(1000,1,0,α1)≤1≤f_ratio(1000,1,0,α2).
(При n=1000 константа и степенная функция представляют из себя практически «незначительный множитель»).
Затем подберите такое число γ, что 1/2<f_ratio(100,1,γ,α1)≤1≤f_ratio(100,1,γ,α2)
Теперь в качестве C возьмите (f_ratio(10,1,γ,α1)+f_ratio(10,1,γ,α2))/2.
Первое приближение готово. Дальше нужно виртуозно повторять этот цикл, увеличивая n и уточняя полученные константы.
Когда константы будут получены с хорошей точностью, нужно попробовать угадать их точные значения.
Для каждой константы x полезно посмотреть на x,1/x,2x,x/2,1/(2x),2/x,x2,2x2,x2/2 и т.п., среди подобных чисел должны встретиться знакомые.
Если константы правильные, то число f_ratio(107,C,γ,α) будет отличаться от 1 не больше, чем на 10−8.
Не так плохо, учитывая, что 10000000!≈1.2024234⋅1065657059.
В этой задаче мы будем исследовать случайные блуждания.
Случайное блуждание — математическая модель процесса случайных изменений — шагов в дискретные моменты времени.
Будем рассматривать самый простой случай: в каждый момент времени делается шаг либо «налево», либо «направо».
Итак, стартуем из точки (0,0) и делаем n шагов: либо (1,1), либо (1,−1), причём направление выбираем случайным образом. Получившаяся кривая и есть случайное блуждание.
На вход даются числа n и k.
Постройте график k случайных блужданий с n шагами.
Для того, чтобы сделать случайный выбор, используйте следующий код:
import random # Разные функции для генерации псевдослучайных последовательностей
random.seed(179)
# random.seed — специальная команда для того,# чтобы последовательность «случайных» чисел была одной и той же# при разных запусках
direction = random.choice((1, -1))
Проведите серию экспериментов.
Попробуйте понять, какая кривая «ограничивает» множество точек всех графиков, когда n=k=100,200.
Опишите, как «ведут» себя кривые при n=10000 и k=10.