Универсальный линейный интерполятор: как справиться с DateTime? - PullRequest
5 голосов
/ 03 марта 2010

Я хотел бы написать класс LinearInterpolator, где X - это тип значения оси X, а Y - тип значения оси Y. Я не вижу, как сделать это так, чтобы X мог быть DateTime или double. Класс похож на приведенный ниже (который не проверен):

class LinearInterpolator<X, Y>
{
    private List<X> m_xAxis;
    private List<Y> m_yAxis;

    public LinearInterpolator(List<X> x, List<Y> y)
    {
        m_xAxis = x;
        m_yAxis = y;
    }

    public Y interpolate(X x)
    {
        int i = m_xAxis.BinarySearch(x);
        if (i >= 0)
        {
            return m_yAxis[i];
        }
        else
        {
            // Must interpolate.
            int rightIdx = ~i;
            if (rightIdx >= m_xAxis.Count)
                --rightIdx;
            int leftIdx = rightIdx - 1;

            X xRight = m_xAxis[rightIdx];
            X xLeft = m_xAxis[leftIdx];
            Y yRight = m_yAxis[rightIdx];
            Y yLeft = m_yAxis[leftIdx];

            // This is the expression I'd like to write generically.
            // I'd also like X to be compilable as a DateTime.
            Y y = yLeft + ((x - xLeft) / (xRight - xLeft)) * (yRight - yLeft);
            return y;
        }
    }
}

}

Это было бы легко в C ++, но я новичок в дженериках C #, поэтому любая помощь будет оценена.

Ответы [ 4 ]

1 голос
/ 03 марта 2010

Следует знать, что C # не поддерживает переопределение операторов. Так что такой код не работает.

Одним из решений, как сказал Спулсон, является не использовать дженерики, а использовать int или long вместо T и использовать DateTime.Ticks.

1 голос
/ 03 марта 2010

Нет хорошего способа сделать математику из обобщений C #, поэтому вы должны сделать что-то вроде этого:

Y y = FromDouble<Y>(ToDouble(yLeft) + ((ToDouble(x) - ToDouble(xLeft)) /
          (ToDouble(xRight) - ToDouble(xLeft))) *
          (ToDouble(yRight) - ToDouble(yLeft)));

double ToDouble(object val)
{
    if (val is DateTime)
        return (double)((DateTime)val).Ticks;
    else
        return Convert.ToDouble(val);
}

T FromDouble<T>(double val)
{
    if (typeof(T) == typeof(DateTime))
        return (T)Convert.ChangeType(new DateTime((long)val), typeof(T));
    else
        return (T)Convert.ChangeType(val, typeof(T));
}

Я не тестировал код, поэтому считаю его псевдокодом.

1 голос
/ 03 марта 2010

Используйте DateTime.Ticks в качестве интерполированного значения. Вы можете использовать тип long в качестве универсального для интерполяции между временами.

0 голосов
/ 03 марта 2010

Спасибо за совет. Я меняю свой подход и пишу интерполятор, который работает только для двойников; Я хочу, чтобы интерполяция была быстрой, поэтому не выполняйте проверки типов во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...