воскресенье, 24 июля 2011 г.

Треугольная периодическая функция

Задача. Есть алгоритм, работающий с некоторым рядом значений. Нужно учесть периодичность следующего характера: например, 1, 2, 1, но не 1, 2, 0; значения в общем случае действительные, целочисленные использованы здесь для простоты). Т. е. нужна функция, принимающая на вход значение без учета периодичности и возвращающая корректное значение с учетом периодичности, так, чтобы возвращаемое значение принадлежало валидному диапазону.

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

Не буду долго тянуть - далее код, выполняющий задачу и пояснения, как он работает и почему именно так.

/*!
 Represents triangular periodic function with shape 
 {min, min}, {max, max}, {min, min} and period equal to 2*(max - min).
 Third parameter are value that needs to be bound 
 within min and max using periodic nature of function.
*/
inline float TriangularPeriodicFunction(float min, float max, float val)
{
 // shifting coordinate system so function is above x axis now
 // (and performing inverse shift when result is obtained)
 if (min < 0)
  return TriangularPeriodicFunction(0, max - min, val - min) + min;

 // function is symmetric relative to axis of values
 val = fabs(val);
 
 // length of monotonous interval (MI)
 float len = max - min;
 // index of MI
 int d = (int) floor(val/len);
 // index of value within MI
 float m = fmod(val, len); 

 if (d >= 0)
  // MI is at the right side (relative to the y axis)
  return d&1 
   ? max - m // values within MI are decreasing
   : m; // values within MI are increasing
 else
  // MI is at the left side (relative to the y axis)
  return d&1 
   ? m - max // values within MI are increasing
   : m; // values within MI are decreasing
}

Сначала производится сдвиг системы координат, так, чтобы график оказался над осью абсцисс - пример ниже. Это необходимо для однозначного определения положения интервала относительно оси значений.

До преобразования (функция с минимумом -2, максимумом 2):

После преобразования:

После этого определяется индекс монотонного интервала (МИ) с целью узнать - возрастает ли он, или убывает.

А далее все совсем просто: если МИ возрастает, то необходимо вернуть значение, взятое по модулю длины интервала (назовем его M), иначе вернуть то же значение за вычетом максимума (MAX) для интервала, находящегося слева от оси значений или разность MAX - M для интервала, находящегося справа от оси значений. В конце, если нужно, производится обратный сдвиг системы координат (первая-вторая строки кода функции).

Код протестирован и работает для действительных чисел.

Комментариев нет:

Отправить комментарий