以下代码非常重复:
public static double Interpolate(double x1, double y1, double x2, double y2, double x)
{
return y1 + (x - x1) * (y2 - y1) / (x2 - x1);
}
public static decimal Interpolate(decimal x1, decimal y1, decimal x2, decimal y2, decimal x)
{
return y1 + (x - x1) * (y2 - y1) / (x2 - x1);
}
但是,我尝试使用泛型不会编译:
public static T Interpolate<T>(T x1, T y1, T x2, T y2, T x)
{
return y1 + (x - x1) * (y2 - y1) / (x2 - x1);
}
错误消息如下:
错误2运算符' - '不能应用于'T'和'T'C类型的操作数:\ Git ... \ LinearInterpolator.cs
我应该如何重用我的代码?
编辑:快速运行时对此模块很重要。
答案 0 :(得分:4)
您当前的代码是正常的 - 如果不将双精度转换为小数,可能是最好的。
通用解决方案可能,但会涉及相当多的基础设施 - 以至于它会使事情过于复杂。
答案 1 :(得分:4)
每当我需要这样做时,我只需诉诸dynamic
。这样可以正常工作,但可能比你目前的重载要慢一些。
public static T Interpolate<T>(T x1, T y1, T x2, T y2, T x)
{
return y1 + ((dynamic)x - x1) * ((dynamic)y2 - y1) / ((dynamic)x2 - x1);
}
答案 2 :(得分:3)
如果没有在T
上指定基类约束,则不能在泛型中使用运算符。
你可能会做这样的事情:Creating a Math library using Generics in C#但是就个人而言,除非你真的有很多不同的公式,否则我没有太多意思。
还可以为T
动态编译表达式树,从C#编译器生成的'model'树中重写double
/ decimal
之间的类型(保持算术优先级)等等...如果你真的感兴趣我可以发布这样的解决方案的代码(我需要一个小时左右的时间!)。运行时性能会变慢。
答案 3 :(得分:2)
您可以使用IConvertible
。
但性能差异可能很大,具体取决于您的需求。
与使用Single
的方法相比,差异可能会达到近50%。
使用Generic进行100000次迭代,单次使用109ms和156ms。
请参阅此代码(.Net 2):
using System;
using System.Text;
using NUnit.Framework;
namespace ProofOfConcept.GenericInterpolation
{
/// <summary>
/// Proof of concept for a generic Interpolate.
/// </summary>
[TestFixture]
public class GenericInterpolationTest
{
/// <summary>
/// Interpolate test.
/// </summary>
[Test]
public void InterpolateTest()
{
Int16 interpolInt16 = Interpolate<Int16>(2, 4, 5, 6, 7);
Int32 interpolInt32 = Interpolate<Int32>(2, 4, 5, 6, 7);
Double interpolDouble = Interpolate<Double>(2, 4, 5, 6, 7);
Decimal interpolDecimal = Interpolate<Decimal>(2, 4, 5, 6, 7);
Assert.AreEqual((Int16)interpolInt32, (Int16)interpolInt16);
Assert.AreEqual((Double)interpolDouble, (Double)interpolDecimal);
//performance test
int qtd = 100000;
DateTime beginDt = DateTime.Now;
TimeSpan totalTimeTS = TimeSpan.Zero;
for (int i = 0; i < qtd; i++)
{
interpolDouble = Interpolate(2, 4, 5, 6, 7);
}
totalTimeTS = DateTime.Now.Subtract(beginDt);
Console.WriteLine(
"Non Generic Single, Total time (ms): " +
totalTimeTS.TotalMilliseconds);
beginDt = DateTime.Now;
for (int i = 0; i < qtd; i++)
{
interpolDouble = Interpolate<Double>(2, 4, 5, 6, 7);
}
totalTimeTS = DateTime.Now.Subtract(beginDt);
Console.WriteLine(
"Generic, Total time (ms): " +
totalTimeTS.TotalMilliseconds);
}
/// <summary>
/// Interpolates the specified x1.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="x1">The x1.</param>
/// <param name="y1">The y1.</param>
/// <param name="x2">The x2.</param>
/// <param name="y2">The y2.</param>
/// <param name="x">The x.</param>
/// <returns></returns>
public static T Interpolate<T>(T x1, T y1, T x2, T y2, T x) where T : IConvertible
{
IConvertible x1C = x1 as IConvertible;
IConvertible y1C = y1 as IConvertible;
IConvertible x2C = x2 as IConvertible;
IConvertible y2C = y2 as IConvertible;
IConvertible xC = x as IConvertible;
Decimal retDec = y1C.ToDecimal(null) +
(xC.ToDecimal(null) - x1C.ToDecimal(null)) *
(y2C.ToDecimal(null) - y1C.ToDecimal(null)) /
(x2C.ToDecimal(null) - x1C.ToDecimal(null));
return (T)((IConvertible)retDec).ToType(typeof(T), null);
}
/// <summary>
/// Interpolates the specified x1.
/// </summary>
/// <param name="x1">The x1.</param>
/// <param name="y1">The y1.</param>
/// <param name="x2">The x2.</param>
/// <param name="y2">The y2.</param>
/// <param name="x">The x.</param>
/// <returns></returns>
public static Single Interpolate(Single x1, Single y1, Single x2, Single y2, Single x)
{
Single retSing = y1 + (x - x1) * (y2 - y1) / (x2 - x1);
return retSing;
}
}
}