更新时间:作者:小小条
C# 11 和 .NET 7 引入了泛型数学(Generic Math)功能,这是一个革命性的特性,允许开发者编写适用于多种数值类型的通用数学算法。这是通过静态抽象接口成员实现的,解决了长期以来在泛型代码中处理数学运算的难题。
// 定义包含静态抽象成员的接口public interface IAddable<T> where T : IAddable<T>{ static abstract T operator +(T left, T right);}// 实现接口public struct MyNumber : IAddable<MyNumber>{ public int Value { get; } public MyNumber(int value) => Value = value; public static MyNumber operator +(MyNumber left, MyNumber right) => new MyNumber(left.Value + right.Value);}
// 基本数值接口public interface INumber<TSelf> : IAdditionOperators<TSelf, TSelf, TSelf>, ISubtractionOperators<TSelf, TSelf, TSelf>, IMultiplyOperators<TSelf, TSelf, TSelf>, IDivisionOperators<TSelf, TSelf, TSelf>, IComparisonOperators<TSelf, TSelf, bool>, IModulusOperators<TSelf, TSelf, TSelf>, IMinMaxValue<TSelf> where TSelf : INumber<TSelf>?{ static abstract TSelf Zero { get; } static abstract TSelf One { get; } static abstract TSelf Abs(TSelf value); static abstract TSelf Max(TSelf x, TSelf y); static abstract TSelf Min(TSelf x, TSelf y);}
// 泛型求和函数public static T Sum<T>(IEnumerable<T> values) where T : INumber<T>{ T result = T.Zero; foreach (T value in values) { result += value; } return result;}// 泛型平均值函数public static T Average<T>(IEnumerable<T> values) where T : INumber<T>{ T sum = T.Zero; int count = 0; foreach (T value in values) { sum += value; count++; } return sum / T.CreateChecked(count);}// 使用示例int[] ints = { 1, 2, 3, 4, 5 };double[] doubles = { 1.1, 2.2, 3.3, 4.4, 5.5 };Console.WriteLine(Sum(ints)); // 输出: 15Console.WriteLine(Average(doubles)); // 输出: 3.3
// 泛型数学运算public static T Calculate<T>(T a, T b) where T : INumber<T>{ return (a + b) * (a - b) / T.CreateChecked(2);}// 使用不同的数值类型Console.WriteLine(Calculate(10, 5)); // int: (10+5)*(10-5)/2 = 37Console.WriteLine(Calculate(10.5, 5.5)); // double: (10.5+5.5)*(10.5-5.5)/2 = 40
using System;using System.Collections.Generic;using System.Linq;using System.Numerics;static T Average<T>(IEnumerable<T> src) where T : INumber<T>{ if (src == null) throw new ArgumentNullException(nameof(src)); T sum = T.Zero; long count = 0; foreach (var x in src) { sum += x; count++; } if (count == 0) throw new InvalidOperationException("sequence empty"); // 将 long 转换为 T(CreateChecked/Truncating/Saturating 都可选) T countT = T.CreateChecked<long>(count); return sum / countT;}
CreateChecked<TOther> / CreateTruncating<TOther> / CreateSaturating<TOther> 在 INumberBase<T> 上定义,用于跨数值类型安全转换(会抛异常、截断或饱和)。
using System.Numerics;static T Gcd<T>(T a, T b) where T : IBinaryInteger<T>{ a = T.Abs(a); b = T.Abs(b); while (b != T.Zero) { var r = a % b; a = b; b = r; } return a;}
IBinaryInteger<T> 提供 %、DivRem、LeadingZeroCount 等整型专用工具。
using System.Numerics;static T Hypot<T>(T x, T y) where T : IFloatingPointIeee754<T>{ // IFloatingPointIeee754 / IRootFunctions 提供 Hypot / Sqrt / Cbrt 等 return T.Hypot(x, y); // 或者 return T.Sqrt(x * x + y * y);}
IFloatingPointIeee754 继承了 IRootFunctions、IPowerFunctions 等,支持 Sqrt, Pow, Hypot 等静态函数。
public class Matrix<T> where T : INumber<T>{ T[,] _a; public int R => _a.GetLength(0); public int C => _a.GetLength(1); public Matrix(int r, int c) => _a = new T[r,c]; public T this[int i,int j] { get => _a[i,j]; set => _a[i,j] = value; } public static Matrix<T> Multiply(Matrix<T> A, Matrix<T> B) { if (A.C != B.R) throw new ArgumentException("size"); var C = new Matrix<T>(A.R, B.C); for (int i = 0; i < A.R; i++) for (int j = 0; j < B.C; j++) { T sum = T.Zero; for (int k = 0; k < A.C; k++) sum += A[i,k] * B[k,j]; C[i,j] = sum; } return C; }}
// 泛型复数计算public record Complex<T>(T Real, T Imaginary) where T : INumber<T>{ public static Complex<T> operator +(Complex<T> left, Complex<T> right) => new Complex<T>(left.Real + right.Real, left.Imaginary + right.Imaginary); public static Complex<T> operator *(Complex<T> left, Complex<T> right) => new Complex<T>( left.Real * right.Real - left.Imaginary * right.Imaginary, left.Real * right.Imaginary + left.Imaginary * right.Real ); public T Magnitude() where T : IRootFunctions<T> { return T.Sqrt(Real * Real + Imaginary * Imaginary); } public override string ToString() => #34;{Real} + {Imaginary}i";}// 使用复数var c1 = new Complex<double>(3, 4);var c2 = new Complex<double>(1, 2);var sum = c1 + c2;var product = c1 * c2;Console.WriteLine(#34;Sum: {sum}"); // 4 + 6iConsole.WriteLine(#34;Product: {product}"); // -5 + 10iConsole.WriteLine(#34;Magnitude: {c1.Magnitude()}"); // 5
public static T StandardDeviation<T>(IEnumerable<T> values) where T : INumber<T>, IRootFunctions<T>{ var mean = Mean(values); var variance = T.Zero; var count = T.Zero; foreach (var value in values) { var diff = value - mean; variance += diff * diff; count++; } variance /= count; return T.Sqrt(variance);}public static T Mean<T>(IEnumerable<T> values) where T : INumber<T>{ var sum = T.Zero; var count = T.Zero; foreach (var value in values) { sum += value; count++; } return sum / count;}
public record Vector2D<T>(T X, T Y) where T : INumber<T>, IRootFunctions<T>{ public T Magnitude => T.Sqrt(X * X + Y * Y); public static Vector2D<T> operator +(Vector2D<T> a, Vector2D<T> b) => new(a.X + b.X, a.Y + b.Y); public static Vector2D<T> operator -(Vector2D<T> a, Vector2D<T> b) => new(a.X - b.X, a.Y - b.Y); public static T Dot(Vector2D<T> a, Vector2D<T> b) => a.X * b.X + a.Y * b.Y; public Vector2D<T> Normalize() { var mag = Magnitude; return mag == T.Zero ? this : new Vector2D<T>(X / mag, Y / mag); }}
public static T CalculateCompoundInterest<T>( T principal, T annualRate, int years, int compoundingPeriods = 1) where T : IFloatingPoint<T>{ var ratePerPeriod = annualRate / T.CreateChecked(compoundingPeriods); var periods = years * compoundingPeriods; return principal * T.Pow(T.One + ratePerPeriod, T.CreateChecked(periods));}
// 泛型数值积分public static T Integrate<T>( Func<T, T> function, T from, T to, int steps) where T : IFloatingPoint<T>{ T stepSize = (to - from) / T.CreateChecked(steps); T sum = T.Zero; for (int i = 0; i < steps; i++) { T x1 = from + T.CreateChecked(i) * stepSize; T x2 = from + T.CreateChecked(i + 1) * stepSize; T y1 = function(x1); T y2 = function(x2); // 梯形法则 sum += (y1 + y2) * stepSize / T.CreateChecked(2); } return sum;}// 使用数值积分Func<double, double> f = x => x * x; // f(x) = x²double integral = Integrate(f, 0.0, 1.0, 1000);Console.WriteLine(#34;∫x²dx from 0 to 1 = {integral}"); // 约等于 0.333...
// 泛型向量类public struct Vector<T> where T : INumber<T>{ private readonly T[] _components; public Vector(params T[] components) { _components = components; } public int Dimension => _components.Length; public T this[int index] { get => _components[index]; set => _components[index] = value; } public static Vector<T> operator +(Vector<T> left, Vector<T> right) { if (left.Dimension != right.Dimension) throw new ArgumentException("Vectors must have the same dimension"); T[] result = new T[left.Dimension]; for (int i = 0; i < left.Dimension; i++) { result[i] = left[i] + right[i]; } return new Vector<T>(result); } public static T operator *(Vector<T> left, Vector<T> right) // 点积 { if (left.Dimension != right.Dimension) throw new ArgumentException("Vectors must have the same dimension"); T result = T.Zero; for (int i = 0; i < left.Dimension; i++) { result += left[i] * right[i]; } return result; } public T Magnitude() where T : IRootFunctions<T> { T sumOfSquares = T.Zero; foreach (T component in _components) { sumOfSquares += component * component; } return T.Sqrt(sumOfSquares); } public override string ToString() => #34;[{string.Join(", ", _components)}]";}// 使用向量var v1 = new Vector<double>(1, 2, 3);var v2 = new Vector<double>(4, 5, 6);var sum = v1 + v2;var dotProduct = v1 * v2;Console.WriteLine(#34;v1 + v2 = {sum}"); // [5, 7, 9]Console.WriteLine(#34;v1 · v2 = {dotProduct}"); // 32Console.WriteLine(#34;|v1| = {v1.Magnitude()}"); // 3.741...
// 泛型统计函数public static class Statistics<T> where T : INumber<T>, IFloatingPoint<T>{ public static T Mean(IEnumerable<T> values) { T sum = T.Zero; int count = 0; foreach (T value in values) { sum += value; count++; } return sum / T.CreateChecked(count); } public static T Variance(IEnumerable<T> values) { T mean = Mean(values); T sumOfSquares = T.Zero; int count = 0; foreach (T value in values) { T deviation = value - mean; sumOfSquares += deviation * deviation; count++; } return sumOfSquares / T.CreateChecked(count); } public static T StandardDeviation(IEnumerable<T> values) { return T.Sqrt(Variance(values)); } public static (T Min, T Max, T Median) DescriptiveStats(IEnumerable<T> values) { var sorted = values.OrderBy(v => v).ToArray(); int count = sorted.Length; T min = sorted[0]; T max = sorted[count - 1]; T median = count % 2 == 0 ? (sorted[count / 2 - 1] + sorted[count / 2]) / T.CreateChecked(2) : sorted[count / 2]; return (min, max, median); }}// 使用统计函数double[] data = { 1.2, 2.3, 3.4, 4.5, 5.6 };Console.WriteLine(#34;Mean: {Statistics<double>.Mean(data)}");Console.WriteLine(#34;Variance: {Statistics<double>.Variance(data)}");Console.WriteLine(#34;Standard Deviation: {Statistics<double>.StandardDeviation(data)}");var (min, max, median) = Statistics<double>.DescriptiveStats(data);Console.WriteLine(#34;Min: {min}, Max: {max}, Median: {median}");
// 自定义分数类型public readonly struct Fraction : INumber<Fraction>, IComparisonOperators<Fraction, Fraction, bool>, IModulusOperators<Fraction, Fraction, Fraction>{ public long Numerator { get; } public long Denominator { get; } public Fraction(long numerator, long denominator) { if (denominator == 0) throw new DivideByZeroException("Denominator cannot be zero"); // 简化分数 long gcd = Gcd(Math.Abs(numerator), Math.Abs(denominator)); Numerator = numerator / gcd; Denominator = denominator / gcd; // 确保分母为正 if (Denominator < 0) { Numerator = -Numerator; Denominator = -Denominator; } } private static long Gcd(long a, long b) => b == 0 ? a : Gcd(b, a % b); // INumber<Fraction> 实现 public static Fraction Zero => new Fraction(0, 1); public static Fraction One => new Fraction(1, 1); public static Fraction operator +(Fraction left, Fraction right) { long numerator = left.Numerator * right.Denominator + right.Numerator * left.Denominator; long denominator = left.Denominator * right.Denominator; return new Fraction(numerator, denominator); } public static Fraction operator -(Fraction left, Fraction right) { long numerator = left.Numerator * right.Denominator - right.Numerator * left.Denominator; long denominator = left.Denominator * right.Denominator; return new Fraction(numerator, denominator); } public static Fraction operator *(Fraction left, Fraction right) { return new Fraction( left.Numerator * right.Numerator, left.Denominator * right.Denominator ); } public static Fraction operator /(Fraction left, Fraction right) { return new Fraction( left.Numerator * right.Denominator, left.Denominator * right.Numerator ); } // 其他接口实现... public override string ToString() => #34;{Numerator}/{Denominator}";}// 使用自定义分数类型Fraction f1 = new Fraction(1, 2);Fraction f2 = new Fraction(3, 4);Fraction sum = f1 + f2; // 5/4Fraction product = f1 * f2; // 3/8Console.WriteLine(#34;{f1} + {f2} = {sum}");Console.WriteLine(#34;{f1} × {f2} = {product}");
public static TResult ConvertSafely<TInput, TResult>(TInput value) where TInput : INumber<TInput> where TResult : INumber<TResult>{ try { return TResult.CreateChecked(value); } catch (OverflowException) { return value < TInput.Zero ? TResult.NegativeInfinity : TResult.PositiveInfinity; }}
// 使用泛型数学的向量化操作public static T[] VectorAdd<T>(T[] a, T[] b) where T : IAdditionOperators<T, T, T>, IAdditiveIdentity<T, T>{ if (a.Length != b.Length) throw new ArgumentException("Arrays must be same length"); var result = new T[a.Length]; // 使用 SIMD 优化(如果可用) if (Vector.IsHardwareAccelerated && Vector<T>.IsSupported) { int vectorSize = Vector<T>.Count; int i = 0; for (; i <= a.Length - vectorSize; i += vectorSize) { var va = new Vector<T>(a, i); var vb = new Vector<T>(b, i); (va + vb).CopyTo(result, i); } // 处理剩余元素 for (; i < a.Length; i++) { result[i] = a[i] + b[i]; } } else { // 回退到常规循环 for (int i = 0; i < a.Length; i++) { result[i] = a[i] + b[i]; } } return result;}
public static T SafeDivide<T>(T dividend, T divisor) where T : IDivisionOperators<T, T, T>, IComparisonOperators<T, T, bool>, IAdditiveIdentity<T, T>{ if (divisor == T.AdditiveIdentity) throw new DivideByZeroException(); return dividend / divisor;}
C# 11 和 .NET 7 的泛型数学功能是一个重大突破,它:
解决了长期痛点:终于可以在泛型代码中方便地进行数学运算提供了完整的数学接口体系:覆盖基本运算、比较、三角函数等支持自定义数值类型:可以创建自己的数值类型并集成到数学生态中保持高性能:通过静态抽象接口避免装箱拆箱开销增强类型安全:编译时类型检查,减少运行时错误适用场景:
数学库开发:创建通用的数学算法库科学计算:物理模拟、数值分析等游戏开发:向量、矩阵运算金融计算:高精度数值计算数据处理:统计分析、数据转换版权声明:本文转载于今日头条,版权归作者所有,如果侵权,请联系本站编辑删除