double r2 = dx * dx + dy * dy;
double r3 = r2 * sqrt(r2);
Можно ли вторую строчку заменить на что-нибудь более быстрое? Что-то, что не касается sqrt
?
double r2 = dx * dx + dy * dy;
double r3 = r2 * sqrt(r2);
Можно ли вторую строчку заменить на что-нибудь более быстрое? Что-то, что не касается sqrt
?
Я думаю, что другой способ взглянуть на ваш вопрос был бы «как вычислить (или приблизить) sqrt (n)». Оттуда ваш вопрос будет тривиальным (n * sqrt (n)). Конечно, вам нужно будет определить, с какой ошибкой вы можете жить. Википедия предлагает множество вариантов:
http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
Как насчет
double r3 = pow(r2,1.5);
Если sqrt реализован как частный случай pow, это сэкономит вам умножение. По большому счету, не так уж много!
Если вы действительно хотите повысить эффективность, подумайте, действительно ли вам нужно r ^ 3. Если, например, вы только тестируете его (или что-то на его основе), чтобы увидеть, превышает ли он определенный порог, то вместо этого проверьте r2, например.
const double r3_threshold = 9;
//don't do this
if (r3 > r3_threshold)
....
//do do this
const double r2_threshold = pow(r3_threshold,2./3.);
if (r2 > r2_threshold)
....
Таким образом, pow
будет вызываться только один раз, возможно, даже во время компиляции.
РЕДАКТИРОВАТЬ. Если вам нужно каждый раз пересчитывать порог, я думаю, что ответ, касающийся Q_rsqrt, заслуживает внимания и, вероятно, заслуживает того, чтобы превзойти этот
r2*r2*r2 > r3_thresh*r3_thresh
?
- person dantswain; 09.12.2011
pow
, но требует дополнительных умножений и код менее понятен
- person Sideshow Bob; 09.12.2011
dx*dx + dy*dy < r_thresh*r_thresh
; кубическая версия меня бы не бросила. Кроме того, если читабельность действительно была проблемой, вы могли бы скрыть ее в макросе или встроенном. пожать плечами
- person dantswain; 09.12.2011
pow
вычисляется только во время компиляции или один раз при запуске программы
- person Sideshow Bob; 09.12.2011
Используйте быстрый обратный sqrt (возьмите функцию Q_rsqrt
).
У вас есть:
float r2;
// ... r2 gets a value
float invsqrt = Q_rsqrt(r2);
float r3 = r2*r2*invsqrt; // x*x/sqrt(x) = x*sqrt(x)
ПРИМЕЧАНИЕ. Для double
типов существует такая константа, как 0x5f3759df
, которая может помочь вам написать функцию, которая обрабатывает также double
типы данных.
ПОЗДНЕЕ РЕДАКТИРОВАНИЕ: похоже, что метод уже обсуждался здесь.
LATER EDIT2: константа для double
была в ссылке:
Ломонт указал, что «магическим числом» для 64-битного типа IEEE754 size type double является 0x5fe6ec85e7de30da, но на самом деле оно близко к 0x5fe6eb50c7aa19f9.
rsqrtss
на Intel, frsqrte
на КПП, vrsqrte
на ARM).
- person Stephen Canon; 09.12.2011
r^2*r^2/sqrt(r^2)
по-прежнему актуальна, независимо от того, используете ли вы трюк Quake или аппаратную 1/sqrt
инструкцию.
- person MSalters; 09.12.2011
r
этоsqrt(dx * dx + dy * dy)
. - person GManNickG   schedule 09.12.2011dx
иdy
вы можете выполнить расширение Тейлора: например, если вы знаете, чтоdy
мало по сравнению сdx
, тогда вы можете приблизитьr3
какdx(dx^2 + 3/2 * dy^2)
(я думаю, что у меня есть это право). РЕДАКТИРОВАТЬ: Вау, это странно, AzzA! - person James   schedule 09.12.2011sqrt
, чтобы люди знали, что они пытаются победить? Использует ли ваш компилятор SSE (или, возможно, какой-то эквивалент для других архитектур)? - person Steve Jessop   schedule 09.12.2011sqrtss
, за которым следуетmul
, то в любом случае мало что может быть правдоподобным. Частично суть моего вопроса заключается в том, что исправление может заключаться в использовании параметра компилятора-m
. - person Steve Jessop   schedule 09.12.2011