| 23.10.2011 12:00 | |
Здравствуйте, сегодня я бы хотел поделиться интересным и неожиданным для меня результатом, с которым я столкнулся, участвуя в семинаре по алгебраической сложности. Речь пойдет о всем известной еще со школы задаче вычисления значения многочлена в точке.
Здесь будет рассмотрен самый быстрый метод, но со сложным предподсчетом. Метод с чуть более худшим временем, зато простым препроцессингом будет описан в следующей части.
Полимиальные функции как инструмент используются в рекордном количестве задач по математике, программированию и других точных науках. Они возникают в различных задачах от генерации ландшафтов, до факторизации чисел. Поэтому о мотивации к эффективному решению данной задачи можно не говорить вовсе.
Для начала рассмотрим формулировку и тривиальный способ решения. Пусть нам дан многочлен от одной переменной:
В нем ровно n + 1 слагаемое и он однозначно задается вектором своих коэффициентов. Известный со школы метод вычисления значения этой функции называется схемой Горнера и заключается в том, что мы представляем исходный многочлен в виде:
С точки зрения алгебраической сложности, можно трактовать это как программу, не содержащую инструкций ветвления (Straight Line Program, SLP), вычисляющую полином f за n умножений и n сложений. Формально:
Оказывается, что, если в такой программе разрешить умножать на любые вещественные числа (а не только коэффициенты исходного многочлена), существуют гораздо более оптимальные варианты. Доказано, что нельзя сделать это быстрее чем за n/2 + 2 умножения (n/2 + 1 при n > 9), см. [1], результат Motzkin(1955), Belaga(1958), Winograd(1970), а так же, что задача требует n сложений.
Первый алгоритм, который я хочу описать, довольно сложный при предподсчете, но зато самый быстрый по количеству операций при вычислении значения многочлена.
Представим исходный полином в виде:
Таким образом, g(x) многочлен на коэффициентах при четных степенях, а h(x) на нечетных:
Предположим, что многочлен h(x) имеет ровно deg(h) корней. Справедливо замечание, что для вещественных чисел это не всегда так, но эту проблему мы устраним позже. Возьмем первый корень t1 многочлена h и поделим g(x) на (x - t1):
Как видно, мы получили многочлен f1, который раскладывается аналогично (1) на сумму g1 и x*h1 в точке x^2. При этом корни h1 - это все оставшиеся корни h. Тогда продолжим процесс аналогично, до тех пор, пока многочлен hk не выродится в константу (и не будет иметь корней):
Прослеживается аналогия со схемой Горнера. Осталось заметить, что левую часть можно вычислить за 2k сложений и k умножений, gk(x^2) вычисляется все той же схемой Горнера за n / 2 - k умножений и столько же сложений (деля g на (x^2 - ti), мы уменьшали степень хотя бы на один k раз), еще одно умножение от x * hk. И надо не забыть про вычисление x * x.
Итого не более (n / 2 + 2) умножения и n сложений. На стадии препроцессинга необходимо найти:
1. корни h(x) - (t1, t2, ..., tk)
2. остатки от деления g(x) - (r1, r2, ..., rk)
3. коэффициенты того, что осталось от g, т.е. gk
Если рассматривать поле комплексных чисел (или любое алгебраически замкнутое поле), то задача решена. Давайте разберемся с вещественным случаем, в котором многочлен h(x) может категорически не захотеть разлагаться. Тут все будет несколько сложнее, чем программа девятого класса.
Докажем вспомогательное утверждение: Если
1. коэффициенты p(x) и q(x) - вещественные.
2. все корни f(x) = p(x) + i * q(x) t1, t2, ..., tn такие, что их мнимая часть строго положительна.
То все корни p(x) и q(x) - вещественные.
Доказательство:
x - корень либо p(x), либо q(x). Тогда:
Но этого обязывает x лежать на вещественной оси, т.к. все числа ti находятся в верхней комплексной полуплоскости.
Вернемся к исходной функции f. Рассмотрим ее смещение вдоль вещественной оси f1(x) = f(x + c). Понятно, что существует такое вещественное c, что все корни f1 будут в правой комплексной полуплоскости. Возьмем и будем вычислять f1 вместо f, для этого нам надо показать, что в разложении:
f_1(x) = g_1(x^2) + xh_1(x),
все корни h1(x) - вещественные.
Все корни f2(x) = f1(-ix) будут в верхней полуплоскости. (умножение комплексного на i - поворот на 90 град.).
Тогда f2(x) = f1(-i*x) = g1(-x^2) - i*x*h1(-x^2) и -x*h1(-x^2) имеет вещественные корни, тогда и h1(x) имеет вещественные корни.
Таким образом, у нас будет одно дополнительное сложение, чтобы вычислять x1 = x - c, по сравнению с предыдущим случаем.
А на стадии препроцессинга все совсем стало грустно:
1. необходимо вычислить комплексные корни f
2. по ним найти c (как минимум вещ. частей)
3. после этого пересчитать его коэффициенты в коэффициенты f1.
4. для f1 выполнить препроцессинг для предыдущего случая.
Вторую часть материала "Вычисление многочлена" можно прочитать тут.
Пожалуйста, обратитесь к странице Уведомление об оптимизации для более подробной информации относительно производительности и оптимизации в программных продуктах компании Intel.
Комментарии (1) 
Обратная ссылка (0)
Оставить комментарий 
Для получения технической помощи посетите сайт службы поддержки.
Авторизация
Автор
adavydow
|


Gulchehra