Shone.Math开源系列1 — 基于.NET 5实现Math<T>泛型数值计算
2021-02-18 04:19
标签:osi ash rabl center oat 覆盖 run review 支持ie .NET 5 preview 4已经可用了,从微软Build2020给出的信息看,.NET 5将实现框架统一,.NET 6将实现界面统一。开源的.NET更加有活力,咱们也从基础开始贡献一点微薄力量,拥抱开源,拥抱.NET未来。 Shone.Math是一个支持Math .NET 2.0开始支持泛型编程,支持IEnumerable 但是对于基础类似的数值运算,.NET没有默认泛型实现方式。StackOverflow上有大量关于泛型数值计算的讨论,C#9.0的部分草案建议也提出添加对泛型计算的支持。 在大量处理数据时,特别是几何或空间数据计算时,泛型数值计算的主要优势是: (1)可重用:专注于数值计算算法,不用为每种数据编写实现,提高开发效率; (2)无装箱:直接支持各种数值类型,减少struct数值类型无装箱和拆箱,提高运行效率; (3)动态切换:可在运行时动态切换数据类型,从float, double, decimal,根据需要可随时提高计算精度,平衡计算性能和存储占用。 泛型数值计算优势这么多,那就赶快实现吧。但是彻底实现有点难,真的难,需要语言、甚至编译器底层支持。对于.net和C#语言是这样,其他大部分语言也是这样。 泛型数值计算的难点在于: (1)数值类型很多:.NET有13中基础数值类型,包括bool, char, byte, sbyte, short, ushort, int, uint, long, ulong, float, double, decimal。除此之外,还有我自己编写实数类Real及其派生类Ration,IrrationXXX等,另有11种。(C#比较全面,其他语言略有差异) (2)运算能力不同:浮点数支持大部分计算,整数只支持+-*/,char和bool型支持的更少,不支持运算编译会报错。(各语言类似) (3)运算实现差异:.NET CLR为了提高效率,int, float, double等符号运算直接使用指令实现,在类型定义中找不到方法,而decimal则使用运算符重载实现。(其他语言应该也有类似技巧) (4)泛型实现机制:.NET泛型属于运行时泛型,泛型T的可使用方法需要从约束推导。由于int, float, double等是系统特殊类型,其基类直接是object,没有暴露.Add/Multiply虚方法,也没有提供静态运算符扩展重载,因此没法直接从object做泛型。其实通过dynamic也可以,但动态类型开销巨大,而且必须进行装箱、拆箱,不是好办法。(C++等采用编译时模板实现泛型的,比较容易实现数值泛型,其他语言java以及动态语言有装箱、拆箱问题) (5)泛型数据转换:泛型T在动态运行时如何与其他数据进行转换也是个难题,而且要求避免装箱、拆箱问题。(编译时泛型语言实现比较困难,而动态语言有装箱、拆箱问题) (6)动态类型切换:在运行时动态切换数据类型,这个更难(静态语言较难,动态语言有优势)。 总之,泛型数值计算确实很难,各种实现都有利弊,否则微软应该在.NET2.0推出时就有解决方案,肯定是经过平衡取舍,只好留给开发者根据需要自己实现了。 Shone.Math有针对性解决了大部分上述障碍,填了很多坑,尽量做到易用性、性能等各方面平衡。各位有兴趣可以到开源项目地址,下载dll试用或代码研究一下,有BUG、问题或建议可以在上面直接提出来,也可以pull参与项目代码完善和实现。 泛型数值计算实现方法很多,不外乎通过inerface、struct、以及delegate这三种进行各种姿势的补锅。我个人研究下来,interface实现很难避开装箱拆箱问题,struct需要组装等开销也不小使用不便,delegate是微软留给这个问题解决办法的一线生机,虽然还有小遗憾,但总体优雅直接。 delegate大家都知道,其实就是.NET托管世界的函数指针,对应C/C++函数指针功能。数值计算各类符号和函数说白了不就是函数调用,完全可以用函数指针、或delegate动态表达,不需要各种代码直接表达。那C#打开unsafe模式,也有函数指针,为什么不用呢?因为C#的指针是简化版,不支持泛型。现在很清楚了,只能用delegate,那么在哪里用呢? 平时不管大家编什么程序,应该都用过Math.Abs, Cos, Sin, Log, Exp等函数吧,主要支持double数值各种计算,.NET Core中后来还提供了MathF静态类,提供对应的float数值各种计算。看到这里应该有点明白了吧,与其每种数据类型写一个MathXXX静态类,不如直接提供一个Math 从上面叙述可以看出,Math public static class Math { //各种常量 public static T MinValue; public static T MaxValue; public static T Epsilon; public static T NegativeInfinity; public static T PositiveInfinity; public static T NaN; public static T Zero; public static T One; public static T MinusOne; public static T PI; public static T E; public static T RadFactor; public static T DegFactor; //各种方法 public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static TryParseDelegate TryParse; public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func public static Func } Math (1)有默认实现:所有常量都有默认值,方法都有默认实现,可能效率不高,但支持所有数据类型,而且可根据需要覆盖重载。这样整数(包括bool和char)也能进行各种Log, Sin运算,只不过运算结果进行了取整,不会报错。 (2)一次静态初始化:每个类型的初始化放在Math (1)24个数值类型全部支持:其他自定义类型只要提供相关实现,也可以扩展支持到Math (2)统一提供所有运算符:不管数据类型,来者不拒,统统支持。 (3)共性默认,个性重载:所有实现方法提供默认算法实现,常用热点函数直接使用反射,从数据类型、Math、MathF、甚至DecimalEx等中抓取delegate进行覆盖重载,性能与原始实现接近。 (4)数值和引用泛型都支持:int, float, double等系统特殊类型为struct,直接按强类型运算,无装箱拆箱开销。Real等实数类型为object引用类型,可自由转换,也无装箱拆箱开销。 (5)统一提供泛型数据转换:从上面的Math (6)为动态切换奠定基础:有了Math Shone.Math只有一个dll文件,除了.NET5系统外无任何外部依赖。注意:Shone.Math支持.NET5以上版本,一方面是拥抱未来向前看,另一方面是开始时发现.NET4和.NET5差好多内容,如MathF类,Math.Asinh,Acosh,Atanh,还有各种Span 1、安装Visual Studio 2019 更新到最新版,在选项设置中打开.net preview支持。 2、下载nuget包或github代码 Nuget包:https://www.nuget.org/packages/Shone.Math/1.0.0 源代码:https://github.com/shonescript/Shone.Math/releases 3、引用nuget包或Shone.Math.dll到你的项目中 4、添加命名空间using Shone; 5、愉快地使用Math using Shone; // import Shone namespace var d = Math var x = 5m.Pow(3); // write in dot style var ds = new double[]{5m, 6m, 7m}.Pow(3); // calculate array easily 由于.NET目前暂不支持泛型静态运算符扩展重载,因此还无法使用+,-,*,/等符号书写泛型计算表达式,编程代码有所冗余。不过据说C#9.0会解决该问题,那就拭目以待,如果有Shone.Math会站第一排给予支持了。 没有运算符,做一下sin((x+y)/2)泛型计算的代码刚开始是这样: Math 这很罗嗦了,为此Shone.Math专门提供了MyNum的扩展类,可以简化成那样: x.Add(y).Divide(FromInt(2)).Sin() 这不就是传说中的Linq流派写法,已经比较接近符号写法了,你说还要哪样。 Shone.Math通过各种精巧实现,提供了统一的泛型数值计算静态类Math 今年初我个人开始全面转向使用.NET 5开发,感觉非常简洁顺畅,结合C#语言新特性nuget和github工作流。基于.NET和C#语言层面开发已经酸爽无比,社区各类开源项目也在不断增强,希望也从自己做起,通过Shone.Math为.NET社区做点贡献。 声明:原创文章欢迎转载,但请注明出处,https://www.cnblogs.com/ShoneSharp。 Shone.Math开源系列1 — 基于.NET 5实现Math 标签:osi ash rabl center oat 覆盖 run review 支持ie 原文地址:https://www.cnblogs.com/ShoneSharp/p/ShoneMath-1.htmlShone.Math开源系列1 — 基于.NET 5实现Math
作者:Shone
一、.NET泛型数值计算优势
二、.NET泛型数值计算难点
三、Shone.Math泛型实现方法
1、关键在于delegate和Math
2、Math
3、Math
4、Math
四、Shone.Math泛型使用方法
五、Math
六、小结
文章标题:Shone.Math开源系列1 — 基于.NET 5实现Math<T>泛型数值计算
文章链接:http://soscw.com/index.php/essay/56888.html