.NET 7+中INumber<T>转float?整数与float互转插值问题
整数转浮点计算后转回整数的线性插值实现方案
当前的LinearBetween泛型方法存在核心问题:当T为整数类型(如int)时,所有运算会执行整数除法,直接截断小数部分,导致斜率m计算错误,最终插值结果完全偏离预期。比如示例中(3-5)/(10-0)会得到0而非-0.2,返回结果为3,但正确的浮点计算结果应为1.6,四舍五入后是2。
以下是两种可行的解决方案:
方案1:泛型方法内统一转浮点计算,再转回原类型
修改泛型方法,将所有参数转换为float执行浮点运算,最后根据原类型决定是直接转换还是四舍五入:
void Main() { Interpolation.LinearBetween((0, 5), (10, 3), 7).DumpIt(); // 输出2 Interpolation.LinearBetween((0.0f, 5f), (10f, 3f), 7f).DumpIt(); // 输出1.6 } 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> { // 将所有参数转换为float执行浮点运算 float x1Float = float.CreateTruncating(a.x1); float y1Float = float.CreateTruncating(a.y1); float x2Float = float.CreateTruncating(b.x2); float y2Float = float.CreateTruncating(b.y2); float xFloat = float.CreateTruncating(x); float m = (y2Float - y1Float) / (x2Float - x1Float); float n = y2Float - m * x2Float; float resultFloat = xFloat * m + n; // 根据类型转换回T:整数类型四舍五入,浮点类型直接转换 if (typeof(T).IsInteger()) { return T.CreateRoundingToEven(resultFloat); } else { return T.CreateTruncating(resultFloat); } } public static int RoundToInt(this float value) { return (int)Math.Round(value); } public static void DumpIt(this object toDump) { Console.WriteLine(toDump); } }
方案2:重载方法分别处理整数和浮点类型
通过重载方法,为整数类型单独实现转浮点计算的逻辑,浮点类型直接使用原有逻辑:
void Main() { Interpolation.LinearBetween((0, 5), (10, 3), 7).DumpIt(); // 输出2 Interpolation.LinearBetween((0.0f, 5f), (10f, 3f), 7f).DumpIt(); // 输出1.6 } public static class Interpolation { // 整数专用版本:内部转浮点计算后返回四舍五入结果 public static int LinearBetween((int x1, int y1) a, (int x2, int y2) b, int x) { float x1f = a.x1; float y1f = a.y1; float x2f = b.x2; float y2f = b.y2; float xf = x; float m = (y2f - y1f) / (x2f - x1f); float n = y2f - m * x2f; return (int)Math.Round(xf * m + n); } // 浮点类型通用版本 public static T LinearBetween<T>((T x1, T y1) a, (T x2, T y2) b, T x) where T : IFloatingPoint<T> { var m = (b.y2 - a.y1) / (b.x2 - a.x1); var n = b.y2 - m * b.x2; return x * m + n; } public static int RoundToInt(this float value) { return (int)Math.Round(value); } public static void DumpIt(this object toDump) { Console.WriteLine(toDump); } }
内容的提问来源于stack exchange,提问作者Matze
相关产品推荐
相关产品推荐

