Почему не стоит пользоваться функцией std::pow для целых чисел?
1,00
р.
р.
Мне не раз приходилось встречать рекомендации по типу "не пользуйтесь функцией std::pow". В связи с чем многие дают эту рекомендацию? void MyPow(int& a, int n) { int c = a for (size_t i = 0 i < n i++) a *= c } Данная функция будет быстрее, чем стандартный std::pow? Или данную рекомендацию дают из-за того, что std::pow реализован не бинарно, а линейно (вот этого я кстати не знаю бинарный он или нет)?
Ответ Вынужден извиниться заранее - я хочу поговорить о применимости pow вообще, а не только для целочисленных значений. Даже если вы хотите возводить в степень умножением - то не надо делать это столь прямолинейно, есть метод быстрого возведения в степень n со скоростью O(lg n). Далее, как и любой совет, это совет, а не догма. Этот совет совершенно справедлив, например (и я его постоянно даю в таких ситуациях), когда начинают вычислять что-то типа pow(-1,n) (сами догадаетесь, как это вычислить быстро и точно?) или pow(x,2) - потому что даже в том же VC++ pow с целочисленной степенью в реализована как (выбросил лишнее для понимания) double pow(double _Xx, int _Yx) noexcept { if (_Yx == 2) return (_Xx * _Xx) return pow(_Xx, static_cast(_Yx)) } Так какой смысл в постоянной проверке равно ли два - двум? :) При малых значениях степени также может оказаться, что непосредственное вычисление быстрее, чем вызов функции. Если вы намекаете на шаблонную реализацию типа pow - то, выбрасывая несущественное для понимания, в VC++ она выглядит так: template && is_arithmetic_v<_Ty2>>> _Common_float_type_t<_Ty1, _Ty2> pow(const _Ty1 _Left, const _Ty2 _Right) { // bring mixed types to a common type using _Common = _Common_float_type_t<_Ty1, _Ty2> return (pow(static_cast<_Common>(_Left), static_cast<_Common>(_Right))) } Т.е. все равно сводится к обычной pow с плавающей точкой. Которая начинает выполнять ряд телодвижений по проверке аргументов и т.п., так что простая замена на exp(y*log(x)) работает несколько быстрее (впрочем, эта разница существенно зависит от используемой модели с плавающей запятой - у VC++ 2017 от практически равных при /fp:fast до разницы в 1.8 раза при /fp:precise). Кстати, думаю (точнее - знаю :), см. P.P.S.), если применить даже ваш линейный способ вычисления - он будет опережать стандартный до достаточно больших значений степени. Точность при возведении в степень целочисленного значения также страдает, но об этом уже писали выше. Словом, всякий инструмент хорош, когда правильно применен. Еще одно замечание в связи с последней фразой - меня также раздражает, когда начинают использовать pow для вычисления какого-нибудь ряда типа
когда каждый член вычисляется возведением в степень, а не умножением на x, или когда так же в лоб вычисляют полином, игнорируя схему Горнера. Здесь применение pow глупо не потому, что она плоха, а потому, что здесь вообще не требуется возведение в степень! P.S. А вообще, в программировании, как и во многих других областях деятельности - в том же кино масса примеров - сначала нечто начинают бездумно применять везде просто потому, что научились использовать это нечто. Потом приходит отрезвление - явный ведь перебор, может, вообще нужно отказаться от такой возможности?.. И только потом приходит понимание, что все хорошо в меру и на своем месте :) Но это так, отвлеченные размышления, не относящиеся к конкретно вопросу.. P.P.S. Не выдержал - заинтересовало, а в самом деле, когда будет быстрее использовать pow, чем просто линейное умножение? Набросал небольшой код, разово просчитал (VC++ 2017), построил график...
Получается, где-то до 30 степени лучше просто множить, чем считать экспоненту от логарифма, и где-то до 50 - если использовать pow. Если использовать быстрое возведение в степень - то эта кривая на графике просто не видна, так как ее значение на всем диапазоне колеблется около 0.25-0.3 мс..