double pow(double, int);
не был удален из спецификации. Его просто переформулировали. Теперь он находится в [c.math]/p11. Как это вычисляется, является деталью реализации. Единственная измененная сигнатура C++03:
float pow(float, int);
Теперь это возвращает двойной:
double pow(float, int);
И это изменение было сделано для совместимости с C.
Пояснение:
26.8 [cmath] / p11 говорит:
При этом должны быть предусмотрены дополнительные перегрузки, достаточные для обеспечения:
Если какой-либо аргумент, соответствующий параметру double, имеет тип long double, то все аргументы, соответствующие параметрам double, эффективно преобразуются в тип long double.
В противном случае, если какой-либо аргумент, соответствующий параметру double, имеет тип double или целочисленный тип, то все аргументы, соответствующие параметрам double, фактически преобразуются в тип double.
В противном случае все аргументы, соответствующие параметрам типа double, фактически преобразуются в число с плавающей запятой.
Этот пункт подразумевает целую массу перегрузок, среди которых:
double pow(double, int);
double pow(double, unsigned);
double pow(double, unsigned long long);
и Т. Д.
Это могут быть фактические перегрузки или они могут быть реализованы с помощью ограниченных шаблонов. Я лично реализовал его в обоих направлениях и решительно поддерживаю ограниченную реализацию шаблона.
Второе обновление для решения проблем с оптимизацией:
Реализация позволяет оптимизировать любую перегрузку. Но помните, что оптимизация должна быть только этим. Оптимизированная версия должна возвращать тот же ответ. Опыт разработчиков таких функций, как pow, заключается в том, что к тому времени, когда вы беретесь за обеспечение того, чтобы ваша реализация, использующая целочисленный показатель степени, давала тот же ответ, что и реализация, использующая показатель степени с плавающей запятой, «оптимизация» часто происходит медленнее.
В качестве демонстрации следующая программа выводит pow(.1, 20)
дважды, один раз с использованием std::pow, а второй раз с использованием «оптимизированного» алгоритма, использующего целочисленный показатель степени:
#include <cmath>
#include <iostream>
#include <iomanip>
int main()
{
std::cout << std::setprecision(17) << std::pow(.1, 20) << '\n';
double x = .1;
double x2 = x * x;
double x4 = x2 * x2;
double x8 = x4 * x4;
double x16 = x8 * x8;
double x20 = x16 * x4;
std::cout << x20 << '\n';
}
В моей системе это распечатывает:
1.0000000000000011e-20
1.0000000000000022e-20
Или в шестнадцатеричной записи:
0x1.79ca10c92422bp-67
0x1.79ca10c924232p-67
И да, разработчики pow действительно беспокоятся обо всех этих битах на нижнем конце.
Таким образом, несмотря на то, что существует свобода перетасовать pow(double, int)
в отдельный алгоритм, большинство разработчиков, которых я знаю, отказались от этой стратегии, за исключением, возможно, проверки очень малых целочисленных показателей. И в этом случае обычно выгодно поместить эту проверку в реализацию с экспонентой с плавающей запятой, чтобы получить максимальную отдачу от ваших затрат на оптимизацию.
person
Howard Hinnant
schedule
11.04.2011
double
, которые, скорее всего, поддерживаются аппаратно и где также можно использовать решение log+mul+exp. - person 6502   schedule 12.04.2011