public static class Interpolation
public static T LinearBetween<T>((T x1, T y1) a, (T x2, T y2) b, T x) where T : INumber<T> =>
LinearBetween<T, double>(a, b, x);
public static T LinearBetween<T, TFloat>((T x1, T y1) a, (T x2, T y2) b, T x)
where T : INumber<T>, INumberBase<T>
where TFloat : IFloatingPoint<TFloat>
if (NumericTypeInformation<T>.IsBinaryInteger)
var floatResult = LinearBetweenUnconverted(
(TFloat.CreateChecked(a.x1), TFloat.CreateChecked(a.y1)),
(TFloat.CreateChecked(b.x2), TFloat.CreateChecked(b.y2)),
TFloat.CreateChecked(x));
var rounded = TFloat.Round(floatResult, MidpointRounding.ToEven);
return T.CreateChecked(rounded);
return LinearBetweenUnconverted(a, b, x);
static T LinearBetweenUnconverted<T>((T x1, T y1) a, (T x2, T y2) b, T x) where T : INumber<T>
var m = (b.y2 - a.y1) / (b.x2 - a.x1);
public static class NumericTypeInformation<TNumber> where TNumber : INumberBase<TNumber>
readonly static Lazy<bool> isBinaryInteger = new Lazy<bool>(
.Where(i => i.IsGenericType)
.Select(i => i.GetGenericTypeDefinition())
.Any(i => i == typeof(IBinaryInteger<>)));
public static bool IsBinaryInteger => isBinaryInteger.Value;
public static class Extensions
public static int RoundToInt(this float value)
return (int)Math.Round(value);
public static void DumpIt(this object toDump)
Console.WriteLine(toDump);
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}.\n", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Interpolation.LinearBetween((0, 5), (10, 3), 7).DumpIt();
Interpolation.LinearBetween((0.0f, 5), (10, 3), 7).RoundToInt().DumpIt();
Assert.That(Interpolation.LinearBetween((0, 5), (10, 3), 7) == Interpolation.LinearBetween((0.0f, 5), (10, 3), 7).RoundToInt());