Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Определение порядка числа вызовов



 

Числа Фибоначчи удовлетворяют отношению

где , т.е.

 

Сложность этого алгоритма – это .

 

Как ускорить?

 

Проблема в том, что мы много раз повторно вычисляем значение функции от одних и тех же аргументов.

 

Третий вопрос: можно ли ускорить алгоритм?

 

Вводим добавочный массив.

 

int fibo(int n)

{

const int MAXN = 1000;

static int c[MAXN];

if (n == 0) return 0;

if (n == 1) return 1;

if (c[n] > 0) return c[n];

return c[n] = fibo(n-1) + fibo(n-2);

}

 

Дерево вызовов модифицированной функции для n = 5

 

 

Проблема с представимостью данных

 

Значение функции растёт слишком быстро, и уже при небольших значениях n число выйдет за пределы разрядной сетки.

 

В реальных программах имеются ограничения на операнды машинных команд.

 

X86, X64 -> int есть 32 бита, longlong есть 64 бита.

 

X86: сложение 32-битных ≈ 1 такт, сложение 64-битных ≈ 3 такта.

X64: сложение 32-битных ≈ 1 такт, сложение 64-битных ≈ 1 такт.

 

X86: умножение 32-битных ≈ 3-4 тактов, умножение 64-битных ≈ 15-50 тактов.

X64: умножение 32-битных ≈ 3-4 такта, умножение 64-битных ≈ 4-5 тактов.

 

Как работать с длинными числами?

 

На 32-битной архитектуре сложение двух 64-разрядных -> сложение младших разрядов и прибавление бита переноса к сумме старших разрядов. Три машинных команды.

 

Числа (n) – те, которые занимают ровно n элементарных типов.

 

int – числа (1), longlong – числа (2).

 

Большие числа требуют представления в виде массивов из элементарных типов.

 

Сколько операций потребуется для сложения двух чисел (n)?

 

Как умножать длинные числа?

 

Школьный алгоритм: O(n2)

 

Алгоритм быстрого умножения

 

Можно ли быстрее?

 

Да. Используя принцип разделяй и властвуй.

 

Быстрый алгоритм умножения был изобретён Гауссом в 19 веке и переизобретён Анатолием Карацубой в 1960-м году.

 

Разделим число (n) на две примерно равные половины:

N1 = Tx1 + y1

N2 = Tx2 + y2

 

При умножении в столбик N1 × N2 = T2x1x2 + T (x1y2 + x2y1) + y1y2

 

Это – четыре операции умножения и три операции сложения.

 

Число T определяет, сколько нулей нужно добавить к концу числа в соответствующей системе счисления.

 

Алгоритм Карацубы

 

Алгоритм Карацубы находит произведение по другой формуле:

 

N1 × N2 = T2x1x2 + T (x1 + y1)(x2 + y2) - x1x2 - y1y2) + y1y2

N1 = 56, N2 = 78, T = 10

x1 = 5, y1 = 6

x2 = 7, y2 = 8

x1x2 = 5 × 7 = 35

(x1 + y1) (x2 + y2) = (5 + 6) (7 + 8) = 11 ∗ 15 = 165

y1y2 = 6 × 8 = 48

N1 × N2 = 35 ∗ 100 + (165 - 35 - 48) ∗ 10 + 48 = 4368

 

Т.е. 3 операции умножения и 6 сложения.

 

Основная теорема о рекурсии

Оценка асимптотического времени алгоритма

 

Как определить, какой порядок сложности будет иметь рекурсивная функция, не проводя вычислительных экспериментов?

 

Рекурсия – разбиение задачи на подзадачи с последующей консолидацией результата.

 

Пусть:

1) a – количество подзадач;

2) размер каждой подзадачи уменьшается в b раз и становится ;

3) сложность консолидации пусть – это O(nd).

 

Время работы такого алгоритма, выраженное рекуррентно – это

 

Основная теорема о рекурсии

 

Пусть для некоторых a > 0, b > 1, d ≥ 0. Тогда

 

 

Оценка сложности алгоритма Карацубы

 

Коэффициент порождения задач a = 3.

 

Коэффициент уменьшения размера подзадачи b = 2.

 

Консолидация решения производится за время O(n) -> d = 1

 

Так как 1 < log23, то это третий случай теоремы -> сложность алгоритма – это

 

Операция умножения чисел (n) при умножении в столбик имеет порядок сложности O(n2).

 

Много операций сложения -> при малых N выгоднее “школьный” алгоритм.

 

Ещё о сложности

Введём вектор-столбец , состоящий их двух элементов последовательности Фибоначчи, и умножим его справа на матрицу :

 

Для вектора-столбца из элементов Fn-1 и Fn умножение на ту же матрицу даст:

 

Таким образом,

 

Возведение в степень

 

Для нахождения n-го числа Фибоначчи достаточно вычислить

 

Можно ли возвести число в n-ую степень за число операций, меньших n - 1?

 

Быстрое вычисление степеней

 

Возведение в квадрат – это умножение на себя.

 

х16 = (х8)2 = ((х4)2)2 = (((х2)2)2)2

 

х18 = (х9)2 = ((х8 * х)2)2 = (((х2)2)2 * х)2

 

Рекуррентная формула

 

Рекурсивная функция быстрого умножения

 

SomeType – некий тип данных.

 

SomeType pow(SomeType x, int n)

{

if (n == 0) return (SomeType)1;

if (n % 2! = 0) return pow(x, n-1) * x;

SomeType y = pow(x, n/2);

return y*y;

}

 

Оценка сложности быстрого умножения

 

25 = 110012

 

n – нечётное -> обнуление последнего разряда.

 

n – чётное -> вычёркивание последнего разряда.

 

Каждую из единиц требуется уничтожить, не изменяя количества разрядов.

 

Каждый из разрядов требуется уничтожить, не изменяя количества единиц.

 

Сложность – O(log N).


Поделиться:



Последнее изменение этой страницы: 2017-03-17; Просмотров: 387; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.029 с.)
Главная | Случайная страница | Обратная связь