![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Скорость вычисления функции оставляет желать..
pirate © (2007-05-18 07:53:00)В общем говоря, народ, такая вот проблема:
Мне потребовалась функция, почти как синус, но сигнал треугольный.
Вот что получилось:
function tri(angle:real):real;
begin
while angle>=2*pi do angle:=angle-2*pi;\\
while angle<0 do angle:=angle+2*pi;\\Ограничиваем угол в [0..2pi]
if angle<pi/2 then
result:=2*angle/pi
else if angle<1.5*pi then
result:=-2*(angle-pi/2)/pi+1
else if angle<2*pi then
result:=2*(angle-1.5*pi)/pi-1;
end;
И теперь я столкнулся с замедлением, связанным с вычислением этой функции.
Какие есть предложения по улучшению алгоритма?
Сергей М. (2007-05-21 16:02:00) [1]
> логичнее ограничивать угол при его вычислении, чем встраивать
> такие возможности в функции-генераторы
Ну может и так.
Спор тут беспредметен.
> Автор делает что-то вроде программного осциллографа
Тогда логичней было бы оперировать аргументом-временем, а не углом.
Jeer (2007-05-21 15:56:00) [2]
> Сергей М. © (21.05.07 15:06) [17]
Автор делает что-то вроде программного осциллографа.
На мой взгляд, логичнее ограничивать угол при его вычислении, чем встраивать такие возможности в функции-генераторы.
Впрочем, соглашусь, что последнее - более безопасно.
Вычисление угла
A := A + dA
if A > 2PI then A := A - 2PI;
Сергей М. (2007-05-21 15:06:00) [3]
> Jeer © (21.05.07 14:56) [16]
Я не стал упрощать, потому что [0..2*PI]-ограничение области определения аргумента, imho, блажь. И Автор уже получил граблями (на тестировании твоего примера) из-за этой блажи)
Jeer (2007-05-21 14:56:00) [4]
> Сергей М. © (21.05.07 12:00) [14]
>
>
Тогда уж еще проще, в случае 0..2*PI
if angle < PI then Result := 1
else Result := -1;
Jeer (2007-05-21 14:33:00) [5]
> pirate © (21.05.07 11:41) [13]
У тебя в вопросе диапазон ограничен 0..2*PI
Вот и ограничивай его для Triangle.
Сергей М. (2007-05-21 12:00:00) [6]
> зачем Max? Разве Sign(Sin) не есть искомый результат?
Max нужен для приведения результата работы Sign к двум значениям - 0 и 1 (Sign возвращает -1, 0, 1, что не соответствует условию задачи)
Привести же результат вызова Max к множеству (-1, 1) проще простого.
Можно поступить еще проще:
Result := Sign(Sin(Angle));
if Result = 0 then Result := -1;
pirate (2007-05-21 11:41:00) [7]Sorry, сам доехал, когда уже отправил.
Решение действительно предельно простое.
Только вот зачем Max? Разве Sign(Sin) не есть искомый результат?
По поводу Triangle: У меня она все время растет, и выдает очень большие значения, такие, что мне на осциллографе(часть программы) приходится ставить усиление(коэффициент обыкновенный) около 0.0001 чтобы наблюдать функцию. Вполне вероятно, что я где-то накосячил, но вроде бы я просто скопировал-вставил. Только у меня функция имеет тип real, вот и все различие.
Спасибо за оперативность! Я просто удивлен..
Сергей М. (2007-05-21 11:25:00) [8]Result := Max(Sign(Sin(Angle), 0);
Jeer (2007-05-21 11:23:00) [9]
> т.е. 1 если alpha [0..pi] и -1 если alpha [pi..2pi].
Ты даже с этим справиться не можешь ?
> function Triangle(Value: double): double; - Не пашет. Точнее
> пашет, но не правильно.
У меня "пашет" и правильно.
Сергей М. (2007-05-21 11:18:00) [10]
> как работает frac
Функция возвращает значение дробной части аргумента.
pirate (2007-05-21 11:14:00) [11]function Triangle(Value: double): double; - Не пашет. Точнее пашет, но не правильно. Что в прочем одно и т о же... :)
SmartTri меня вполне удовлетворил. Большое спасибо.
Но из одного ответа появляется новый вопрос:
В справке я не понял, как работает frac, видимо я по математическй части просто не знаю чего-то. Следовательно я не понял, как работает SmartTri. И вот теперь такое дело: Надобно аналогичную функцию, но сигнал квадратный, т.е. 1 если alpha [0..pi] и -1 если alpha [pi..2pi].
Ну, вот собственно и все.
Jeer (2007-05-18 12:25:00) [12]Еще вариант, при условии угла 0..1, что не ограничивает, конечно
Скорость примерно та же.
function Triangle3(omega: double): double;
begin
if omega <= 0.25 then Result := 4 * omega
else
if omega >= 0.75 then
Result := 4 * (omega - 1)
else
Result := 4 * (0.5 - omega);
end;
Jeer (2007-05-18 11:47:00) [13]Так чуть быстрее, вроде:)
7-8 kTicks, а от Mbo 8-9 kTicks
function Triangle(Value: double): double;
var B: double;
d: integer;
const Pi2 = Pi / 2;
Pi2I = 1 / Pi2;
begin
d := 1;
B := Value + Pi2;
if (B > Pi) then begin
B := B - Pi;
d := -1;
end;
if (B > Pi) then begin
B := B - Pi;
d := 1;
end;
Result := d * (Pi2I * B - 1);
end;
DVM (2007-05-18 10:40:00) [14]Функция tri на маленьких значениях углов быстрее SmartTri в 2 раза
На больших значениях медленнее в сотни раз.
DVM (2007-05-18 10:31:00) [15]Я не знаю, заменяет ли оптимизатор pi/2 на заранее вычисленное значение, но можно еще заранее вычислить pi/2, и поместить в константу.
MBo (2007-05-18 09:29:00) [16]Так в справке же описано
pirate (2007-05-18 09:19:00) [17]Меня всегда интересовала функция Frac() - ты не мог бы доступно пояснить ее?
MBo (2007-05-18 09:02:00) [18]так проще:
Angle := (Angle + Pi/2) / Pi;
d := 2 * Frac(Abs(Angle)) - 1;
if Odd(Trunc(Angle)) then
d := -d;
MBo (2007-05-18 09:01:00) [19]Да уж - циклы зачем-то...
function SmartTri(Angle: Double): Double;
var
d: Double;
begin
Angle := Angle + Pi/2;
d := 2 * Frac(Abs(Angle) / (Pi)) - 1;
if Odd(Trunc(Angle / Pi)) then
d := -d;
Result := d;
end;