Как быстро возвести число в степень
Перейти к содержимому

Как быстро возвести число в степень

Ускоряем pow

В этой статье я хочу поделиться несколькими нестандартными алгоритмами для быстрого возведения числа в степень, а также продемонстрировать их реализацию и сравнить их быстродействие в C++, C# и Java.

Сравнить точность алгоритмов можно прямо сейчас на этой странице.

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

1%, а иногда и вовсе без неё.

Содержание

Алгоритмы (5 штук)

На повестке дня у нас есть 5 алгоритмов: «Старая аппроксимация», «Бинарная степень», «Делящая быстрая степень», «Дробная” быстрая степень» и «Другая” аппроксимация».
Названия алгоритмам я придумал сам (за исключением бинарной степени), так как нигде не нашёл официальных версий, но вы можете называть их иначе.

Для расчета прироста скорости и погрешности будем сравнивать эти методы со стандартными функциями pow, Math.Pow и Math.pow в C++, C# и Java соответственно. О том, как производилось сравнение, будет сказано в частях “Сравнение производительности” и “Сравнение точности”.

Алгоритм: «Старая аппроксимация»

Увеличение скорости: в

11 раз
Погрешность: <2%
Ограничения: приемлемая точность только для степеней от -1 до 1

Реализация в C# и Java

Этот метод основан на алгоритме, использованном в игре Quake III Arena 2005 года. Он возводил число x в степень -0.5, т.е. находил значение:

Разработчики для этого написали такую функцию

Узнал я об этом методе из статьи «Магическая константа» 0x5f3759df. В ней подробно объясняется как работает этот код и как его можно улучшить для работы с любой степенью и double’ми вместо float’ов. В моих кодах также есть магическая константа 4606853616395542500L. Нашёл я её по следующей формуле (она описана в статье выше):

Число 1.0730088 было подобрано вручную для достижения наибольшей точности вычислений.

Алгоритм: Бинарное возведение в степень

Увеличение скорости: в среднем в

7.5 раз, преимущество сохраняется до возведения чисел в степень 134217728 в C++/C# и 4096 в Java.
Погрешность: нет, но стоит отметить, что операция умножения не ассоциативна для чисел с плавающей точкой, т.е. 1.21 * 1.21 не то же самое, что 1.1 * 1.1 * 1.1 * 1.1, однако при сравнении со стандартными функциями погрешности, как уже сказано ранее, не возникает.
Ограничения: степень должна быть целым числом не меньше 0

Реализация в C# и Java

Широко известный алгоритм для возведения любого числа в целую степень с абсолютной точностью. Принцип действия прост: есть целая степень e, чтобы получить число b в этой степени нужно возвести это число во все степени 1, 2, 4, … 2 n (в коде этому соответствует b *= b), каждый раз сдвигая биты e вправо (e >>= 1) пока оно не равно 0 и тогда, когда последний бит e не равен нулю ((e & 1) != 0), домножать результат v на полученное b.
Пример: возвести 2 в степень 5.
v = 1, e = 5 = 1012, b = 2
Шаги цикла:

e = 1012 — последний 1 → v *= b → v = 2
b *= b → b = 4
e >>= 1 → e = 102 = 2

e = 102 — последний 0 → пропускаем
b *= b → b = 16
e >>= 1 → e = 1

e = 12 — последний 1 → v *= b → v = 32
.
e = 0 → выход из цикла

Результат: v = 32, что и есть 2 5 .

Алгоритм: «Делящая быстрая степень»

Увеличение скорости: в

13%
Примечание: в коде ниже присутствуют проверки для особых входных данных. Без них код работает всего на 10% быстрее, но погрешность возрастает в десятки раз (особенно при использовании отрицательных степеней).

Реализация в C# и Java

Узнав о методе аппроксимации чисел в степенях от -1 до 1 и о бинарном методе, мне захотелось объединить их для создания функции, которая могла бы быстро возводить число в любую степень. Для этого я придумал следующую формулу:

Мы разбиваем степень на две части: e / el, которая всегда меньше или равна 1, и el, которая является целым числом. Теперь для расчета x^(e / el) мы можем использовать “старую” аппроксимацию, а для x^el — бинарную степень.Таким образом, объединяя этих два узкоспециализированных метода, мы получили универсальный метод. Но эту идею можно реализовать по-другому.

Алгоритм: «Дробная быстрая степень»

Увеличение скорости: в

Реализация в C# и Java

По сути, любое число состоит из суммы двух частей: целой и дробной. Целую можно использовать для возведения основания в степень при помощи бинарного возведения, а дробную — при помощи “старой” аппроксимации.

В результате получаем следующую формулу:

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

Алгоритм: «Другая аппроксимация»

Увеличение скорости: в

9 раз
Погрешность: <1.5%
Ограничения: точность стремительно падает при повышении абсолютного значения степени и остается приемлемой в промежутке [-10, 10]

Реализация в C# и Java

Про историю этого алгоритма я ничего не знаю, я просто нашёл его тут: Optimized pow() approximation for Java, C / C++, and C#. Возможно, если использовать его в “делящей–” и “дробной быстрых степенях» вместо “старой” аппроксимации, можно достигнуть лучшей точности ценой немного меньшей скорости.

Сравнение производительности

Сравнение производительности производилось следующим образом: генерируем 500000 чисел-оснований в промежутке от 0.0 до 99999.0 и 500000 чисел-степеней в промежутке от A до B. Запоминаем текущее время, запускаем цикл на 500000 итераций, вычисляем значение основания в степени через функцию f и результат суммируем в calculationResult. По окончанию цикла снова замеряем время, разница во времени и есть время выполнения. Данная процедура повторяется 20 раз, конечный результат — усредненный за все 20 тестов.

Псевдокод сравнения производительности в C++:

Аналогично измерялась скорость в C# и Java. В репозитории проекта можно посмотреть на реальный код для сравнения производительности в C++, C# и Java.

Тесты производились в каждом языке для степеней в промежутках [-10.5, 0], [0, 2], [0, 10.5], [0, 25.75], [0, 55.5]. Прирост скорости каждого метода по сравнению со стандартным в каждом языке для каждого сета степеней изображен на графиках ниже:

Рассмотреть подробнее результаты тестов можно посмотреть в этой таблице.

Тесты проводились на i5-10300H, 19.8 DDR4 GB usable RAM, 64-битная платформа.
C++: MSVC + /O2 + /Oi + /Ot
C#: optimize code

Сравнение точности

Для рассчитывания точности я возводил очередное число в определенную степень стандартным и одним из нестандартных способами, потом делил большее из полученных чисел на меньшее, складывал все эти отношения вместе, а в конце делил их на количество сравнений. Так и получалось значение погрешности.
Основания и степени генерировались также, как и в алгоритме сравнения производительности.
Для более гибкого и удобного тестирования я создал Blazor страницу, на которой можно построить графики реальных и полученных одним из методов значений чисел, лежащих в заданном промежутке и возведенных в указанную степень:

Ниже на этой же странице можно самим провести сравнение точности каждого метода для всех степеней, лежащих в заданном промежутке:

Вывод

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

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

Спасибо за внимание. Надеюсь эта статья поможет сделать ваш код немного быстрее.

Возведение в степень: правила, примеры

Мы разобрались, что вообще из себя представляет степень числа. Теперь нам надо понять, как правильно выполнять ее вычисление, т.е. возводить числа в степень. В этом материале мы разберем основные правила вычисления степени в случае целого, натурального, дробного, рационального и иррационального показателя. Все определения будут проиллюстрированы примерами.

Понятие возведения в степень

Начнем с формулирования базовых определений.

Возведение в степень — это вычисление значения степени некоторого числа.

То есть слова «вычисление значение степени» и «возведение в степень» означают одно и то же. Так, если в задаче стоит «Возведите число 0 , 5 в пятую степень», это следует понимать как «вычислите значение степени ( 0 , 5 ) 5 .

Теперь приведем основные правила, которым нужно придерживаться при таких вычислениях.

Как возвести число в натуральную степень

Вспомним, что такое степень числа с натуральным показателем. Для степени с основанием a и показателем n это будет произведение n -ного числа множителей, каждый из которых равен a . Это можно записать так:

Как возвести число в натуральную степень

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

Условие: возведите — 2 в степень 4 .

Решение

Используя определение выше, запишем: ( − 2 ) 4 = ( − 2 ) · ( − 2 ) · ( − 2 ) · ( − 2 ) . Далее нам нужно просто выполнить указанные действия и получить 16 .

Возьмем пример посложнее.

Вычислите значение 3 2 7 2

Решение

Данную запись можно переписать в виде 3 2 7 · 3 2 7 . Ранее мы рассматривали, как правильно умножать смешанные числа, упомянутые в условии.

Выполним эти действия и получим ответ: 3 2 7 · 3 2 7 = 23 7 · 23 7 = 529 49 = 10 39 49

Если в задаче указана необходимость возводить иррациональные числа в натуральную степень, нам потребуется предварительно округлить их основания до разряда, который позволит нам получить ответ нужной точности. Разберем пример.

Выполните возведение в квадрат числа π .

Решение

Для начала округлим его до сотых. Тогда π 2 ≈ ( 3 , 14 ) 2 = 9 , 8596 . Если же π ≈ 3 . 14159 , то мы получим более точный результат: π 2 ≈ ( 3 , 14159 ) 2 = 9 , 8695877281 .

Отметим, что необходимость высчитывать степени иррациональных чисел на практике возникает сравнительно редко. Мы можем тогда записать ответ в виде самой степени ( ln 6 ) 3 или преобразовать, если это возможно: 5 7 = 125 5 .

Отдельно следует указать, что такое первая степень числа. Тут можно просто запомнить, что любое число, возведенное в первую степень, останется самим собой:

Как возвести число в натуральную степень

Это понятно из записи .

От основания степени это не зависит.

Так, ( − 9 ) 1 = − 9 , а 7 3 , возведенное в первую степень, останется равно 7 3 .

Как возвести число в целую степень

Для удобства разберем отдельно три случая: если показатель степени — целое положительное число, если это ноль и если это целое отрицательное число.

В первое случае это то же самое, что и возведение в натуральную степень: ведь целые положительные числа принадлежат ко множеству натуральных. О том, как работать с такими степенями, мы уже рассказали выше.

Теперь посмотрим, как правильно возводить в нулевую степень. При основании, которое отличается от нуля, это вычисление всегда дает на выходе 1 . Ранее мы уже поясняли, что 0 -я степень a может быть определена для любого действительного числа, не равного 0 , и a 0 = 1 .

5 0 = 1 , ( — 2 , 56 ) 0 = 1 2 3 0 = 1

0 0 — не определен.

У нас остался только случай степени с целым отрицательным показателем. Мы уже разбирали, что такие степени можно записать в виде дроби 1 a z , где а — любое число, а z — целый отрицательный показатель. Мы видим, что знаменатель этой дроби есть не что иное, как обыкновенная степень с целым положительным показателем, а ее вычислять мы уже научились. Приведем примеры задач.

Возведите 2 в степень — 3 .

Решение

Используя определение выше, запишем: 2 — 3 = 1 2 3

Подсчитаем знаменатель этой дроби и получим 8 : 2 3 = 2 · 2 · 2 = 8 .

Тогда ответ таков: 2 — 3 = 1 2 3 = 1 8

Возведите 1 , 43 в степень — 2 .

Решение

Переформулируем: 1 , 43 — 2 = 1 ( 1 , 43 ) 2

Вычисляем квадрат в знаменателе: 1,43·1,43. Десятичные дроби можно умножить таким способом:

В итоге у нас вышло ( 1 , 43 ) — 2 = 1 ( 1 , 43 ) 2 = 1 2 , 0449 . Этот результат нам осталось записать в виде обыкновенной дроби, для чего необходимо умножить ее на 10 тысяч (см. материал о преобразовании дробей).

Ответ: ( 1 , 43 ) — 2 = 10000 20449

Отдельный случай — возведение числа в минус первую степень. Значение такой степени равно числу, обратному исходному значению основания: a — 1 = 1 a 1 = 1 a .

Пример: 3 − 1 = 1 / 3

9 13 — 1 = 13 9 6 4 — 1 = 1 6 4 .

Как возвести число в дробную степень

Для выполнения такой операции нам потребуется вспомнить базовое определение степени с дробным показателем: a m n = a m n при любом положительном a , целом m и натуральном n .

Таким образом, вычисление дробной степени нужно выполнять в два действия: возведение в целую степень и нахождение корня n -ной степени.

У нас есть равенство a m n = a m n , которое, учитывая свойства корней, обычно применяется для решения задач в виде a m n = a n m . Это значит, что если мы возводим число a в дробную степень m / n , то сначала мы извлекаем корень n -ной степени из а , потом возводим результат в степень с целым показателем m .

Проиллюстрируем на примере.

Вычислите 8 — 2 3 .

Решение

Способ 1. Согласно основному определению, мы можем представить это в виде: 8 — 2 3 = 8 — 2 3

Теперь подсчитаем степень под корнем и извлечем корень третьей степени из результата: 8 — 2 3 = 1 64 3 = 1 3 3 64 3 = 1 3 3 4 3 3 = 1 4

Способ 2. Преобразуем основное равенство: 8 — 2 3 = 8 — 2 3 = 8 3 — 2

После этого извлечем корень 8 3 — 2 = 2 3 3 — 2 = 2 — 2 и результат возведем в квадрат: 2 — 2 = 1 2 2 = 1 4

Видим, что решения идентичны. Можно пользоваться любым понравившимся способом.

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

Возведите 44 , 89 в степень 2 , 5 .

Решение

Преобразуем значение показателя в обыкновенную дробь: 44 , 89 2 , 5 = 44 , 89 5 2 .

А теперь выполняем по порядку все действия, указанные выше: 44 , 89 5 2 = 44 , 89 5 = 44 , 89 5 = 4489 100 5 = 4489 100 5 = 67 2 10 2 5 = 67 10 5 = = 1350125107 100000 = 13 501 , 25107

Ответ: 13 501 , 25107 .

Если в числителе и знаменателе дробного показателя степени стоят большие числа, то вычисление таких степеней с рациональными показателями — довольно сложная работа. Для нее обычно требуется вычислительная техника.

Отдельно остановимся на степени с нулевым основанием и дробным показателем. Выражению вида 0 m n можно придать такой смысл: если m n > 0 , то 0 m n = 0 m n = 0 ; если m n < 0 нуль остается не определен. Таким образом, возведение нуля в дробную положительную степень приводит к нулю: 0 7 12 = 0 , 0 3 2 5 = 0 , 0 0 , 024 = 0 , а в целую отрицательную — значения не имеет: 0 — 4 3 .

Как возвести число в иррациональную степень

Необходимость вычислить значение степени, в показателе которой стоит иррациональное число, возникает не так часто. На практике обычно задача ограничивается вычислением приблизительного значения (до некоторого количества знаков после запятой). Обычно это считают на компьютере из-за сложности таких подсчетов, поэтому подробно останавливаться на этом не будем, укажем лишь основные положения.

Если нам нужно вычислить значение степени a с иррациональным показателем a , то мы берем десятичное приближение показателя и считаем по нему. Результат и будет приближенным ответом. Чем точнее взятое десятичное приближение, тем точнее ответ. Покажем на примере:

Вычислите приближенное значение 2 в степени 1,174367.

Решение

Ограничимся десятичным приближением a n = 1 , 17 . Проведем вычисления с использованием этого числа: 2 1 , 17 ≈ 2 , 250116 . Если же взять, к примеру, приближение a n = 1 , 1743 , то ответ будет чуть точнее: 2 1 , 174367 . . . ≈ 2 1 , 1743 ≈ 2 , 256833 .

Быстрое возведение в степень.

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

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

Пусть имеется некоторая степень x n , где x – действительное число, а n – натуральное. Тогда для x n справедливо равенство:

x n = (x m ) k

При этом m*k=n. Например: 3 6 =(3 3 ) 2 , 5 7 =(5 7 ) 1 . Это свойство является одним из основных степенных свойств, и именно на нем основывается рассматриваемый метод. Далее, заметим, что в случае, если n является четным числом, то верно следующее равенство:

x n = (x n/2 ) 2 = x n/2 * x n/2

Так, если x=3, а n=6, то имеем 3 6 = (3 6/2 ) 2 = 3 6/2 * 3 6/2 . Используя это свойство, удастся существенно уменьшить число операций необходимых для возведения x в степень n. Теперь адаптируем формулу для случая с нечетным n. Для этого понадобиться просто перейти к степени на единицу меньшей. Например: 5 7 = 5 6 *5, 12 5 = 12 4 *12. Общая форма равенства перехода:

x n = x n-1 *x

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *