2013-05-28 2 views
17

Моя программа тратит 90% времени процессора в функции std::pow(double,int). Точность здесь не является главной проблемой, поэтому мне было интересно, есть ли более быстрые альтернативы. Одна вещь, о которой я думал, - это бросить плавать, выполнить операцию, а затем вернуться к двойному (еще не пробовал); Я обеспокоен тем, что это не является переносимым способом повышения производительности (не большинство процессоров работают на двойниках внутренне так или иначе?)Что быстрее, чем std :: pow?

Приветствия

+2

Kinda зависит от того, какие полномочия вы рассчитываете - пожалуйста, покажите код и/или опишите свои данные. – paddy

+1

Аппаратное обеспечение быстрее, чем программное обеспечение в общем случае, это своего рода точка 'pow' ... вы не можете победить его, если не можете наложить дополнительные ограничения на то, что вы делаете. – Mehrdad

+1

Эта статья может быть полезна: http://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/ –

ответ

14

Похоже Martin Ankerl имеет несколько статей по этому вопросу, Optimized Approximative pow() in C/C++ является один и имеет два быстрых версий, один выглядит следующим образом:

inline double fastPow(double a, double b) { 
    union { 
    double d; 
    int x[2]; 
    } u = { a }; 
    u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447); 
    u.x[0] = 0; 
    return u.d; 
} 

, который опирается на тип каламбуров через союз, который не определено поведение в C++, из проекта стандарта секции 9.5[class.union]:

в союзе, в лучшем случае один из не-статических элементов данных может быть ctive в любое время, то есть значение в большинство из нестатических элементов данных могут быть сохранены в объединении в любое время. [...]

но большинство компиляторов включая gcc support this with well defined behavior:

Практика чтения из другого члена союза, чем один совсем недавно написал (так называемый «тип-каламбуров») является распространенным явлением. Даже с -fstrict сглаживанием, типа каламбурная разрешено, при условии, что в памяти осуществляется доступ через типа накидной

, но это не является универсальным, как this article points out и, как я point out in my answer here с помощью memcpy должен генерировать идентичный код и не вызывает неопределенными поведение.

Он также ссылается на второй Optimized pow() approximation for Java, C/C++, and C#.

Первая статья также связывает его microbenchmarks here

9

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

4

Насколько велики ваши целые числа? Известны ли они во время компиляции? Гораздо лучше вычислить x^2 как x*x, а не pow(x,2). Примечание. Почти все приложения pow() для целочисленной мощности включают в себя повышение числа до второй или третьей мощности (или мультипликативного обратного в случае отрицательных показателей). Использование pow() является излишним в таких случаях. Используйте шаблон для этих малых целых степеней или просто используйте x*x.

Если целые числа являются небольшими, но неизвестными во время компиляции, скажем между -12 и +12, умножение все равно будет бить pow() и не потеряет точность. Вам не нужно одиннадцать умножений для вычисления x^12. Четверо будут делать. Используйте тот факт, что x^(2n) = (x^n)^2 и x^(2n + 1) = x * ((x^n)^2). Например, x^12 есть ((x * x * x)^2)^2.Два умножения для вычисления x^3 (x * x * x), еще один для вычисления x^6 и один последний для вычисления x^12.

+0

Конечно, это предполагает, что ausairman работает с целыми числами. Неясно, так ли это. – jamesdlin

+0

@jamesdin: Конечно. * Моя программа тратит 90% времени процессора в функции std :: pow (double, int). * –

+0

Упс, извините. Ты прав; Я думаю, что мой мозг был в отпуске сегодня. > _ < – jamesdlin