tags:

views:

51

answers:

4

I'd like to write a LinearInterpolator class, where X is the type of the X axis value, and Y the type of the Y axis value. I can't see how to do this such that X could be a DateTime or a double. The class is something like below (which is untested):

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;
        }
    }
}

}

It'd be easy in C++, but I'm new to C# generics so any help would be appreciated.

+1  A: 

Use DateTime.Ticks as the interpolated value. You can use a long type as your generic to interpolate between times.

spoulson
If `long` isn't preferred, you could instead use `int` to interpolate intervals from 0..*n* as a tick offset from a base `DateTime`. e.g. `DateTime.AddTicks(offset)`.
spoulson
+1  A: 

One thing to know is that C# does not support operator override. So such a code does not work.

One solution as spoulson said is to not use generics, and use int or long instead of T, and use DateTime.Ticks.

Nicolas Dorier
More accurately, it doesn't support signature-based polymorphism the way C++ templates do, so you can't have a class that's generic over arithmetic types.
Jeffrey Hantin
+1  A: 

There's no good way to do math from C# generics, so you have to do something like this:

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));
}

I haven't tested the code, so consider it pseudo-code.

Gabe
A: 

Thanks for the advice. I'm changing my approach and writing an interpolator that works only for doubles; I want interpolation to be fast, so prefer not to do type checks at run-time.