Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Скорость вычисления функции оставляет желать..


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;


Наверх

Титульная страница Поиск, карта сайта Написать письмо