Shone.Math开源系列2 — 实数类型(含分数和无理数)的实现
Shone.Math开源系列2
实数类型(含分数和无理数)的实现
作者:Shone
声明:原创文章欢迎转载,但请注明出处,https://www.cnblogs.com/ShoneSharp。
摘要: 计算机数值计算存在输入进制误差、计算过程的分数和无理数运算误差,是很多编程开发的痛点所在。开源项目Shone.Math提供了统一的实数类型Real,支持分数和无理数计算,做到精度、性能和存储的各方面平衡,可以消除输入进制误差和分数计算误差,大幅减少无理数的计算过程误差。
Shone.Math是一个支持Math<T>泛型数值计算和Real实数运算(浮点数、分数、PI,E,Log,Exp等无理数)的轻量级基础数学库。该项目开源地址https://github.com/shonescript/Shone.Math,是本人把多年代码积累正式转向.NET 5的第一个开源项目,请大家多多支持了。
本系列博客上个章节详细介绍了Shone.Math的Math<T>的泛型实现,全面支持了系统数值类型。有评论提到了相关数据精度话题,因此今天就把Shone.Math的特色—“实数运算”提前进行介绍。
一、数值计算之殇
大家在编程过程中其实不断在跟各种数值类型打交道,为什么没有可以“一统江湖”的数值类型?目前还真没有!
很多动态语言直接使用double(64位二进制浮点数)作为唯一数值,然并卵,立马就会碰到下面经典的翻车案例,不信你打开编辑器测试下面公式:
0.1+0.2 竟然不等于 0.3,而是等于0.30000000000000004
如果使用整数类型int或long,碰到除法5/2竟然等于2,那更翻车翻的四脚朝天,因此一般通用计算必须采用浮点数就是这个道理,有误差大家都知道,也就将就将就吧。
二、数值误差难点
在有限的时间和空间约束下,计算机数值计算存在误差主要在于三个方面:
(1)输入时进制表达误差:前面的0.1是十进制小数,用二进制浮点数表示会是个无限循环形式,只能截除尾数导致误差。这是最无奈的,一输入就是不精确。那么使用decimal(128位十进制浮点数)就没有这个问题,但是十进制常规CPU不支持,计算速度慢十几倍,大家也不大愿意用,除了金融系统实在没办法。
(2)计算过程的分数运算误差:除法运算可能产生不可规约分数,用小数点表达就是无限循环形式,必须截除尾数,上面的进制转换误差本质上也是分数导致的问题。该问题采用decimal十进制浮点数也没用,只有使用分数形式才能准确表达,那么需要增加一倍存储和接近四倍计算时间的开销。
(3)计算过程的无理数运算误差:类似PI、E、Sqrt、Log、Exp、Sin、Cos、等运算,都可能产生无理数,用小数表达就是无限不循环的形式,真是不死不休,一辈子也算不完!那些超算中心专门为了计算PI都使用高能计算机,还是算不完,这是用啥进制都没用,用分数也不行。这也是分数表达不受待见的原因,你搞半天,碰到无理数运算,误差立马要算总账,没法控制。
无理数运算随时存在,目前还没有很好的解决方案,多数只能采用更高精度的浮点数如quad(128位二进制浮点数)、甚至bigfloat(可指定任意位数精度的二进制浮点数),但带来存储和计算时间增加的开销也很大。
三、Shone.Math实数解决方案
Shone.Math实数有针对性解决了大部分上述问题,填了很多坑,尽量做到易用性、性能等各方面平衡。各位有兴趣可以到开源项目地址,下载dll试用或代码研究一下,有BUG、问题或建议可以在上面直接提出来,也可以pull参与项目代码完善和实现。
Shone.Math实数把数值分为几类,并通过类型派生进行表达和计算重载:
(1)可二进制有效表达的浮点数:结果值是有限不循环的二进制整数或小数,可使用1个double数值(如2.5r,与常规数值相同),放在基类Real中进行表达和计算;
(2)分子分母均可二进制有效表达的分数:结果值是无限循环的二进制浮点数,需要采用2个double数值的分数形式(如3\5r,采用反斜杠表示分子分母是一个整体),放在派生类Ration中进行表达和计算;
(3)可间接包含分数系数的各类无理数:结果值是无限不循环的二进制浮点数,但是可以针对常用的部分无理数采用专门的间接表达形式如下,基类为Irration,每个间接无理数都采用2个double数值的分数形式。
a)PI无理数:IrrationPI,如3\5pi,间接表示3/5*PI的计算值;
b)E无理数:IrrationE,如3\5e,间接表示3/5*PI的计算值;
c)Sqrt无理数:IrrationSqrt,如3\5sqt,间接表示sqrt(3/5)的计算值;
d)Sqrd无理数:IrrationSqrd,如3\5sqd,间接表示(3/5)*(3/5)的计算值;
e)Xp无理数:IrrationXp,如3\5xp,间接表示pow(10,3/5)的计算值;
f)Exp无理数:IrrationExp,如3\5exp,间接表示pow(E,3/5)的计算值;
g)Pow无理数:IrrationPow,如3\5pow,间接表示pow(3,5)的计算值;
h)Log无理数:IrrationLog,如3\5ln,间接表示底数为E的ln(3/5)计算值;
i)Log10无理数:IrrationLog10,如3\5lg,间接表示底数为10的lg(3/5)计算值;
j)Logx无理数:IrrationLog,如3\5log,间接表示底数为3的log(3, 5)计算值;
注意,上述有些间接无理数是互补运算(如sqrd与sqrt、xp与log10、exp与log等),如果两个一起会消解,从而保持计算过程的精确性。
(4)其他无法间接表达的无理数:在计算过程中只要碰到这种类型,比如Sin、Cos三角函数等计算结果还是无理数时只能截断尾数,转化为第一类可二进制有效表达的浮点数,仍是Real表达。
四、Shone.Math实数解决问题
Shone.Math的Real实数类型设计和实现上尽量做到精度、性能和存储各方面的平衡考虑,在有限的时间和空间内,可以有效减少计算机数值计算误差。
(1)消除了输入时进制表达误差:0.1将被转化为1\10r的分数表示,没有进制转换问题。
(2)消除了计算过程的分数运算误差:支持纯正的分数运算也没有误差。
(3)减少计算过程的无理数运算误差:大量常用的PI、E、Sqrt、Log、Exp等无理数运算采用间接形式表达,直到实在无法间接表达时再截尾处理产生误差,但总体上将大大减少常规计算的总体误差。
当然无理数运算误差不可能彻底解决,Shone.Math只是提出了一个可行的实现方法,具体好坏还有待在实际应用中考证。
五、Shone.Math实数Real使用方法
Shone.Math只有一个dll文件,除了.NET5系统外无任何外部依赖。注意:Shone.Math支持.NETCore3.1/5.0以上版本,一方面是拥抱未来向前看,另一方面是开始时发现.NET4和.NET5差好多内容,如MathF类,Math.Asinh,Acosh,Atanh,还有各种Span<T>,Memory<T>等高级类型,这也符合.NET5一统江湖的趋势。
1、安装Visual Studio 2019
更新到最新版,在选项设置中打开.net 5 preview支持。
2、下载nuget包或github代码
Nuget包:https://www.nuget.org/packages/Shone.Math/1.0.7
源代码:https://github.com/shonescript/Shone.Math/releases
3、引用nuget包或Shone.Math.dll到你的项目中
4、添加命名空间using Shone;
5、愉快地使用实数常量、方法
using Shone; // import Shone namespace
var d = Real.PI*3; // result is 3pi of IrrationPi
var x = 5.ToReal().Pow(3); // write in dot style
var ds = new double[]{5, 6, 7}.ToReal().Pow(3); // calculate array easily
6、Real也支持作为Math<T>计算
7、注意:Real只有基类对外暴露方法,其他派生类只能在计算过程中自动产生,比如进行Sqrt()时,如果结果可以间接表达,就会产生如3\5sqrt之类的IrrationSqrt无理数,使用时可以体会一下。
六、Real类型的不足之处
前面也说了,Shone.Math的Real类型解决了输入和过程的分数误差,但没有彻底消除无理数误差,只是进行推迟和消解,要进行等值判断时其精度还只能与double类似。
Real类型设计为class,对大量数值计算而言,会产生堆上内存分配和相关GC,对性能有影响。我最早采用的是struct,但需要1个计算结果、2个double分子分母、还有1个byte的标记,占用存储太大,而且有好多判断,不容易调试。最终经过权衡使用现在的方案。
七、小结
基于.NET 5的开源项目Shone.Math,通过各种精巧实现,提供了统一的泛型数值计算静态类Math<T>和实数类型Real,为开发各类自定义数值、几何、空间、公式解析等泛型和高精度数值应用打下了坚实基础。本系列下一章节将介绍Shone.Math的一些.NET5专用高级特性如ref, Span, Memory的泛型数值计算扩展。
声明:原创文章欢迎转载,但请注明出处,https://www.cnblogs.com/ShoneSharp。
标签:Shone.Math 泛型 数值 计算 .NET 5 C#
Shone.Math开源系列2 — 实数类型(含分数和无理数)的实现的更多相关文章
- Shone.Math开源系列1 — 基于.NET 5实现Math<T>泛型数值计算
Shone.Math开源系列1 — 基于.NET 5实现Math<T>泛型数值计算 作者:Shone .NET 5 preview 4已经可用了,从微软Build2020给出的信息看,.N ...
- 智能合约语言Solidity教程系列2 - 地址类型介绍
智能合约语言Solidity教程系列第二篇 - Solidity地址类型介绍. 写在前面 Solidity是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你 ...
- 智能合约语言 Solidity 教程系列3 - 函数类型
Solidity 教程系列第三篇 - Solidity 函数类型介绍. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以 ...
- mybatis入门系列三之类型转换器
mybatis入门系列三之类型转换器 类型转换器介绍 mybatis作为一个ORM框架,要求java中的对象与数据库中的表记录应该对应 因此java类名-数据库表名,java类属性名-数据库表字段名, ...
- 智能合约语言 Solidity 教程系列2 - 地址类型介绍
Solidity教程系列第二篇 - Solidity地址类型介绍. 写在前面 Solidity是以太坊智能合约编程语言,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以太坊是 ...
- GitHub C 和 C++ 开源库的清单(含示例代码)
内容包括:标准库.Web应用框架.人工智能.数据库.图片处理.机器学习.日志.代码分析等. 标准库 C++标准库,包括了STL容器,算法和函数等. C++ Standard Library:是一系列类 ...
- javascript系列-class6.String类型
观察淘宝网商品数据 有一个东西叫服务器>>>>js的作用重要作用之一>>>>交互>>>>人机交互(事件)>>&g ...
- MySQL的死锁系列- 锁的类型以及加锁原理
疫情期间在家工作时,同事使用了 insert into on duplicate key update 语句进行插入去重,但是在测试过程中发现了死锁现象: ERROR 1213 (40001): De ...
- springboot源码解析-管中窥豹系列之项目类型(二)
一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...
随机推荐
- JavaScript Array every()&some()&reduce()方法
every()方法测试数组的所有元素是否都通过了指定函数的测试. // 每一项都要满足条件才会返回true,只要有一项不满足返回false var arr = [1, 2, 3, 4]; let bl ...
- (附音视频、PPT地址)《打开Python这扇窗》分享总结
0.导读 2016年最新开发语言排行榜中,Python已经跃居第三,仅次于C.JAVA.掌握Python已经成为时下运维圈的共识,更让人期待的是,本次公开课分享的嘉宾自身就长期专注Python.Doc ...
- 图论--网络流--最大流 POJ 2289 Jamie's Contact Groups (二分+限流建图)
Description Jamie is a very popular girl and has quite a lot of friends, so she always keeps a very ...
- 谷歌OKR指导手册 (译)
这是一本关于 OKR 迷你小册子,名为<google OKR playbook>,由 www.whatMatters.com 网站发布. 该网站由John Doerr 团队经营, 而Joh ...
- FastDFS文件服务器安装指南附安装包和自启动(看此篇就够了)
安装包在最后,本文为博主自己亲自安装记录 转载请注明出处 注意文字不清晰请放大看,放大看!! 安装包地址
- 软件——IDEA中如何去掉警告虚线
初次安装使用IDEA,总是能看到导入代码后,出现很多的波浪线,下划线和虚线,这是IDEA给我们的一些提示和警告,但是有时候我们并不需要,反而会让人看着很不爽,这里简单记录一下自己的调整方法,供其他的小 ...
- python学习笔记-零碎知识点
1. 绝对值 abs(-4) 结果: 4 2.
- spring的单元测试
如果spring 4.3.18这个版本的spring要使用junit,需要使用junit的junit-4.12之上的版本.使用这个版本junit的时 候需要引入hamcrest-all的jar包.之前 ...
- 消息队列高手课 -笔记-Kafka高性能的几个关键点
总结下kafka 高性能的几个关键点是: 1:使用批量处理的方式 去提升系统的吞吐能力 2:基于磁盘文件高性能的顺序读写的特性来设计存储结构 3:利用操作系统的PageCache 来缓存数据 减少I ...
- Centos7 使用 Ansible 批量安装中文字体
需求背景 Centos7 下 Java 生成图片水印时中文乱码,原因是没有安装中文字体. 安装中文字体 以下是基于 Centos7 手动安装中文字体的详细步骤.当测试或者生产环境服务器比较多的时候,建 ...