Допустим, нам нужно приближённо оценить какую-то величину.
Мы можем просто записать знак ≈.
k=1∑nk1≈lnn+γ
Поль Бахман в книге Analytische Zahlentheorie (1894) ввёл очень удобное обозначение O,
которое позволило заменить знак ≈ на знак = и количественно выразить точность оценки.
k=1∑nk1=lnn+γ+O(n1)
Позже идеи Поля Бахмана развивались другими математиками,
и в итоге был разработан очень мощный математический аппарат,
позволяющий производить самые разные вычисления:
от оценки примерного времени работы алгоритма без привязки к временной сложности базовых операций
до вычисления сложных сумм и интегралов.
Сейчас мы имеем аж целых 5 символов для работы.
Называются эти символы символами Ландау, в честь Эдмурда Ландау,
который ввёл два символа O и o 1909 году.
Позже математическое сообщество расширило обозначения,
добавив Ω, ω и Θ,
а благодаря Дональду Кнуту обозначения Θ и Ω добрались и до информатиков.
О-большое
O(f(x)) — класс функций,
которых функция f асимптотически ограничивает сверху.
Поскольку O(f(x)) (можно любой символ Ландау вставить) формально является множеством,
корректно было бы говорить о принадлежности функций классу,
то есть писать g(x)∈O(f(x)) вместо g(x)=O(f(x)).
Никто не пишет ∈, если речь идет о символах Ландау. Ну так исторически сложилось.
Но вот
g(x)=O(f(x))всегдаозначаетg(x)∈O(f(x))
Свойства символов Ландау
Функция принадлежит своему O-большому. Также работает для остальных символов, кроме o-малого.
f(x)=O(f(x))
Константы, как внутренние, так и внешние, не влияют на класс. Работает для всех символов.
O(a⋅f(x))=O(f(x))иa⋅O(f(x))=O(f(x))приa=0
При сложении результат не выходит из класса. Также работает для Θ и o, но не работает для Ω.
O(f(x))+O(f(x))=O(f(x))
Операция взятия O-большого идемпотентна. Аналогично для остальных.
O(O(f(x)))=O(f(x))
Функции-множители можно безболезненно вносить и выносить из знака O-большого, o-малого, Θ, но не всегда из Ω.
f(x)⋅O(g(x))=O(f(x)⋅g(x))=O(f(x))⋅O(g(x))
Как следствие, любой класс выразим через O(1).
O(f(x))=f(x)⋅O(1)
Операция взятия O-большого транзитивна. Выполняется и для остальных, но для Ω зависит от знака.
f(x)=O(g(x)),g(x)=O(h(x))⟹f(x)=O(h(x))
Применение символов Ландау
Из асимптотической формулы не следует сходимость (ряда или интеграла).
Например, асимптотические формулы, выражающие восходящую и нисходящую степени числа n
Обе асимптотические формулы верны для любого действительного r и любого фиксированного целого m>0.
Однако, сумма
k=0∑∞[1/2−k1/2]n1/2−k
расходится для всех n несмотря на то,
что n1/2−m−1→0 при m→∞.
Так что нельзя путать аппроксимацию с пределом.
Асимптотический ряд — это не бесконечная сумма, стремящаяся к точному значению,
а последовательность всё более точных приближений.
Символы Ландау можно использовать также и для вывода каких-то соотношений.
Например, используя формулу Тейлора для ex, можем провести следующие интересные манипуляции
nn=elnn/n=1+lnn/n+O((lnn/n)2)
Формулу Тейлора мы имели право применить потому что lnn/n→0 при n→∞.
Из этого равенства можно вывести, например,
что n⋅(nn−1)≈lnn:
n⋅(nn−1)=n⋅(lnn/n+O((lnn/n)2))=lnn+O((lnn)2/n)
Иерархия
Доминирование
Говорят "Функция fдоминирует над функцией g" и обозначают f(x)≻g(x), если
f(x)≻g(x)⟺x→alimf(x)g(x)=0⟺g(x)=o(f(x))
Здесь выполняется транзитивность, а значит мы можем расставить множество функций по порядку их роста. Например:
1≺loglogx≺logx≺xc≺xlogx≺cx≺xx
Эквивалентность
Функции f и g называют эквивалентными и обозначают f(x)∼g(x), если
f(x)∼g(x)⟺x→alimg(x)f(x)=1⟺f(x)=g(x)+o(g(x))
Это очень помогает нам при подсчёте пределов, так как эквивалентные функции можно заменять друг на друга без потери точности.
Таковыми являются, например, sin(x) и x при очень маленьких x.
Асимптотика в анализе алгоритмов
Когда мы решаем какую-то задачу, мы хотим оценить, какое решение и когда будет самым лучшим.
Для этого нам надо знать, сколько по времени будет работать программа и сколько оперативной памяти она займёт (меньше — лучше).
Брать в руки секундомер и лупу, чтобы смотреть внутрь компьютера при каждом запуске идея конечно хорошая, но не эффективная.
В ней мы напрямую зависим от мощности процессора, памяти, погодных условий, количества человек в комнате,
количества пылинок в системе охлаждения — не очень круто.
Намного лучше мы поступим, если посмотрим на код программы и посчитаем, сколько раз будет выполняться основная операция
(В сортировках — сравнения, в вычислениях — арифметические операции и т.д.). Но тут можно сильно закопаться, так как
зачастую количество сильно зависит от входных данных, а они бывают очень разными. Тогда придётся смотреть на их распределение,
находить самый лучший случай, самый худший, средний, отклонение от среднего. Это полезно и даже необходимо, когда нам нужно
сравнить два алгоритма примерно одинаковой сложности, но не всегда нужно и не всегда стоит затраченных усилий.
Тут нам на выручку приходят символы Ландау. Они дают понимание того, как алгоритм поведёт себя при росте размерности данных и
позволяют описывать алгоритм не в терминах точного количества операций, а в терминах класса роста этого количества.
Асимптотика в анализе рядов и интегралов
Допустим нам нужно посчитать какой-то интеграл, но функция внутри нам очень очень не нравится. Мы можем
ассимптотически свести к чему-то попроще и посчитать с какой-то точностью.
Ассимптотические оценки интегралов
Пусть функции f(x) и g(x) непрерывны, g(x)>0 при a<x<b и
x0∫bg(x)dx=+∞
где a<x0<b.
Тогда если f(x)=O(g(x)) при x→b, то
x∫bf(x)dx=Ox∫bg(x)dxприx→b
Для f(x)=o(g(x)) при x→b рассуждения аналогичны, но символ O заменяется на o.
В случае, если f(x)∼g(x), можно сказать
x∫bf(x)dx∼x∫bg(x)dxприx→b
А что, если нам известна только асимтотическая оценка функции на бесконечности?
Можем асимптотически оценить её интеграл.
Асимтотическая оценка интеграла по асимптотике функции
Если f(x)=O(xa) при x→+∞, то
0∫xf(t)dt={O(xa+1)приa>−1O(lnx)приa=−1
Если f(x)∼xa при x→+∞, то
0∫xf(t)dt∼{xa+1/a+1приa>−1lnxприa=−1
∞∫xf(t)dt∼a+1xa+1приa<−1
Например для f(x)=x+1/x=O(x1/2) будем иметь 0∫xf(t)dt=O(x3/2)
Бывают также и ситуации, когда мы хотим уточнить асимптотику сходящегося интеграла или оценить сумму ряда.
Для такого существуют асимптотические выражения, позволяющие перейти от суммы к интегралу и от интеграла к сумме.
Переход от суммы к интегралу и наоборот
Пусть f(x)=k=2∑nakx−k+O(x−n−1) при x→+∞, тогда
x∫∞f(t)dt=k=2∑n(k−1)xk−1ak+O(x−n)
Пусть f(x) непрерывна, положительна и монотонна при x⩾0, тогда
k=0∑nf(k)=0∫nf(x)dx+O(f(n+1))+O(1)приx→∞
Например, пусть
f(x)=1/x2−2/x3+O(1/x4)
тогда
x∫∞f(t)dt=x1−x21+O(x31)
Или другой пример, который был упомянут в самом начале.
Пусть
f(x)=x1
Тогда
k=1∑nk1=lnn+O(n1)+O(1)=lnn+γ+O(n1)
Реккурентные соотношения
В анализе асимптотики многих алгоритмов возникают реккурентные соотношения. Например, в бинарном поиске
на отсортированном массиве общее время работы будет зависеть от времени работы поиска в половине массива T(n)=T(n/2)+O(1),
которое, в свою очередь, будет зависеть от времени работы в четверти массива и так далее. Чтобы выяснить, какую асимптотику
имеет время работы такого алгоритма, нам нужно уметь решать реккурентные соотношения.
Посмотрим на изначальное соотношение. Если будем расписывать его дерево рекурсии, то в нём будет logbn уровней.
На каждом уровне количество вершин в дереве будет умножаться на a,
так на уровне i будет ai детей.
Известно, что каждый ребёнок i будет размера n/bi и потребует O((n/bi)c) дополнительных действий.
Следовательно, общее количество операций на уровне i равно
O(ai(bin)c)=O(nc(bca)i)
Заметим, что количество операций на уровне зависит от величины a/bc.
Если эта величина больше единицы, то количество операций растёт,
если меньше — убывает, а если равно единице — остаётся постоянным.
Поэтому рассмотрим три случая: a/bc>1, a/bc=1 и a/bc<1. Из второго получаем: logba=c.
Общее число операций складывается из числа операций на каждом уровне рекурсии:
Случай c>logba. Тогда a/bc<1, и геометрическая прогрессия убывает:
T(n)=O(nc)
Случай c=logba. Тогда a/bc=1, и сумма превращается в logbn одинаковых слагаемых:
T(n)=nci=0∑logbn1=nc+nclogbn=O(nclogn)
Случай c<logba. Тогда a/bc>1, и геометрическая прогрессия растёт:
T(n)=O(nc(bca)logbn)=O(nlogba)
Исчисление сумм
Метод суммирования Эйлера
Одним из самых крутых, методов получение приближённых значений сумм является метод суммирования Эйлера.
Идея метода — аппроксимировать сумму интегралом.
Вот пусть нам надо найти значение суммы k=1∑n−1f(k).
Попытаемся аппроксимировать эту сумму интегралом 1∫nf(x)dx.
где Rm,n — остаточный член, представимый как поправка
Rm,n=m!(−1)m+11∫nBm(xmod1)f(m)(x)dx
Этот остаточный член мал при очень маленьких значениях Bm(xmod1)f(m)(x)/m!.
Фактически, для чётного m
m!Bm(xmod1)⩽m!∣Bm∣<(2π)m4
К сожалению, часто бывает, что при увеличении m функция f(m)(x) возрастает по модулю.
Существует «наилучшее» значение m, при котором ∣Rm,n∣ минимален,
то есть такое m, при котором неприятный остаточный член вносит минимум путаниц в формулу суммы.
Оценивать остаток можно следующим методом:
При чётном m и при условии, что f(m)(x) имеет постоянный знак для всех 1<x<n,
значение остаточного члена по модулю не превосходит значения последнего вычисленного члена, то есть
∣Rm,n∣⩽m!(−1)mBm(f(m−1)(n)−f(m−1)(1))
Существует и более мощное утверждение, накладывающее не такие сильные ограничения на функцию.
При чётном m и при условии, что f(m+2)(x)f(m+4)(x)>0 для всех 1<x<n,
существует такая константа 0<θ<1, что
Rm,n=θ⋅(m+2)!Bm+2(f(m+1)(n)−f(m+1)(1))
Тогда получаем
∣Rm,n∣⩽(m+2)!∣Bm+2∣f(m+1)(n)−f(m+1)(1)
Формула суммирования Эйлера
...
Получение формулы Стирлинга
Применим метод суммирования Эйлера для получение приближённой формулы Стирлинга.
Пусть f(x)=lnx. Применим формулу суммирования Эйлера, получим
Данное равенство специально было записано в более сложном виде, чем это необходимо,
так как неполная гамма-функция γ(n,n) является частью полной гамма-функции γ(n,∞)=Γ(n)=(n−1)!,
а n!en/nn — величина R(n)+Q(n).
Получается, задача анализа сумм P(n), Q(n) и R(n) сводится к нахождению хороших оценок для γ(n,n)/(n−1)!.
Определим приближённое значение γ(x+1,x+y)/Γ(x+1) для фиксированного y и больших x.
По определению имеем