Форум: "Основная";
Текущий архив: 2007.07.29;
Скачать: [xml.tar.bz2];
ВнизСкорость вычисления функции оставляет желать.. Найти похожие ветки
← →
pirate © (2007-05-18 07:53) [0]В общем говоря, народ, такая вот проблема:
Мне потребовалась функция, почти как синус, но сигнал треугольный.
Вот что получилось: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;
И теперь я столкнулся с замедлением, связанным с вычислением этой функции.
Какие есть предложения по улучшению алгоритма?
← →
MBo © (2007-05-18 09:01) [1]Да уж - циклы зачем-то...
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;
← →
MBo © (2007-05-18 09:02) [2]так проще:
Angle := (Angle + Pi/2) / Pi;
d := 2 * Frac(Abs(Angle)) - 1;
if Odd(Trunc(Angle)) then
d := -d;
← →
pirate © (2007-05-18 09:19) [3]Меня всегда интересовала функция Frac() - ты не мог бы доступно пояснить ее?
← →
MBo © (2007-05-18 09:29) [4]Так в справке же описано
← →
DVM © (2007-05-18 10:31) [5]Я не знаю, заменяет ли оптимизатор pi/2 на заранее вычисленное значение, но можно еще заранее вычислить pi/2, и поместить в константу.
← →
DVM © (2007-05-18 10:40) [6]Функция tri на маленьких значениях углов быстрее SmartTri в 2 раза
На больших значениях медленнее в сотни раз.
← →
Jeer © (2007-05-18 11:47) [7]Так чуть быстрее, вроде:)
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;
← →
Jeer © (2007-05-18 12:25) [8]Еще вариант, при условии угла 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;
← →
pirate © (2007-05-21 11:14) [9]function Triangle(Value: double): double; - Не пашет. Точнее пашет, но не правильно. Что в прочем одно и т о же... :)
SmartTri меня вполне удовлетворил. Большое спасибо.
Но из одного ответа появляется новый вопрос:
В справке я не понял, как работает frac, видимо я по математическй части просто не знаю чего-то. Следовательно я не понял, как работает SmartTri. И вот теперь такое дело: Надобно аналогичную функцию, но сигнал квадратный, т.е. 1 если alpha [0..pi] и -1 если alpha [pi..2pi].
Ну, вот собственно и все.
← →
Сергей М. © (2007-05-21 11:18) [10]
> как работает frac
Функция возвращает значение дробной части аргумента.
← →
Jeer © (2007-05-21 11:23) [11]
> т.е. 1 если alpha [0..pi] и -1 если alpha [pi..2pi].
Ты даже с этим справиться не можешь ?
> function Triangle(Value: double): double; - Не пашет. Точнее
> пашет, но не правильно.
У меня "пашет" и правильно.
← →
Сергей М. © (2007-05-21 11:25) [12]Result := Max(Sign(Sin(Angle), 0);
← →
pirate © (2007-05-21 11:41) [13]Sorry, сам доехал, когда уже отправил.
Решение действительно предельно простое.
Только вот зачем Max? Разве Sign(Sin) не есть искомый результат?
По поводу Triangle: У меня она все время растет, и выдает очень большие значения, такие, что мне на осциллографе(часть программы) приходится ставить усиление(коэффициент обыкновенный) около 0.0001 чтобы наблюдать функцию. Вполне вероятно, что я где-то накосячил, но вроде бы я просто скопировал-вставил. Только у меня функция имеет тип real, вот и все различие.
Спасибо за оперативность! Я просто удивлен..
← →
Сергей М. © (2007-05-21 12:00) [14]
> зачем Max? Разве Sign(Sin) не есть искомый результат?
Max нужен для приведения результата работы Sign к двум значениям - 0 и 1 (Sign возвращает -1, 0, 1, что не соответствует условию задачи)
Привести же результат вызова Max к множеству (-1, 1) проще простого.
Можно поступить еще проще:
Result := Sign(Sin(Angle));
if Result = 0 then Result := -1;
← →
Jeer © (2007-05-21 14:33) [15]
> pirate © (21.05.07 11:41) [13]
У тебя в вопросе диапазон ограничен 0..2*PI
Вот и ограничивай его для Triangle.
← →
Jeer © (2007-05-21 14:56) [16]
> Сергей М. © (21.05.07 12:00) [14]
>
>
Тогда уж еще проще, в случае 0..2*PI
if angle < PI then Result := 1
else Result := -1;
← →
Сергей М. © (2007-05-21 15:06) [17]
> Jeer © (21.05.07 14:56) [16]
Я не стал упрощать, потому что [0..2*PI]-ограничение области определения аргумента, imho, блажь. И Автор уже получил граблями (на тестировании твоего примера) из-за этой блажи)
← →
Jeer © (2007-05-21 15:56) [18]
> Сергей М. © (21.05.07 15:06) [17]
Автор делает что-то вроде программного осциллографа.
На мой взгляд, логичнее ограничивать угол при его вычислении, чем встраивать такие возможности в функции-генераторы.
Впрочем, соглашусь, что последнее - более безопасно.
Вычисление угла
A := A + dA
if A > 2PI then A := A - 2PI;
← →
Сергей М. © (2007-05-21 16:02) [19]
> логичнее ограничивать угол при его вычислении, чем встраивать
> такие возможности в функции-генераторы
Ну может и так.
Спор тут беспредметен.
> Автор делает что-то вроде программного осциллографа
Тогда логичней было бы оперировать аргументом-временем, а не углом.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2007.07.29;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.043 c