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 ...
随机推荐
- mac OS 安装 Homebrew软件包管理器
Homebrew macOS 缺失的软件包的管理器 中文官网 https://brew.sh/index_zh-cn 获取安装命令 /usr/bin/ruby -e "$(curl -fsS ...
- Linux下文件完整性监控工具Tripwire详解
Tripwire 是目前最为著名的Unix下文件系统完整性检查的软件工具,这一软件采用的技术核心就是对每个要监控的文件产生一个数字签名,保留下来.当文件现在的数字签名与保留的数字签名不一致时,那么现在 ...
- JAVA连接Excel最好用的开源项目EasyExcel,官方使用文档及.jar包下载
EasyExcel是一个基于Java的简单.省内存的读写Excel的开源项目.在尽可能节约内存的情况下支持读写百M的Excel. github地址:https://github.com/alibaba ...
- codeforce 1311 D. Three Integers
In one move, you can add +1 or −1 to any of these integers (i.e. increase or decrease any number by ...
- ACM-ICPC 2019 山东省省赛 M Sekiro
Sekiro: Shadows Die Twice is an action-adventure video game developed by FromSoftware and published ...
- 说一说Web开发中两种常用的分层架构及其对应的代码模型
昨天妹子让我帮她解决个问题,本以为可以轻松搞定,但是打开他们项目的一瞬间,我头皮发麻.本身功能不多的一个小项目,解决方案里竟然有几十个类库.仅仅搞明白各个类库的作用,代码层次之间的引用关系就花了一个多 ...
- Collections集合工具类常用的方法
java.utils.Collections //是集合工具类,用来对集合进行操作.部分方法如下: public static <T> boolean addAll(Collection& ...
- 使用PXE+Kickstart无人值守安装服务
一. 配置DHCP服务程序 1) 按照图在虚拟机的虚拟网络编辑器中关闭自身的DHCP服务. 2) 当挂载好光盘镜像并把Yum仓库文件配置妥当后,就可以安装DHCP服务程序 ...
- web概念简述,HTML学习笔记
今日内容 1. web概念概述 2. HTML web概念概述 * JavaWeb: * 使用Java语言开发基于互联网的项目 * 软件架构: 1. C/S: Client/Server 客户端/服务 ...
- JDBC06 其他操作及批处理Batch
灵活指定SQL语句中的变量 -PreparedStatement 对存储过程进行调用 -CallableStatement 运用事务处理 -Transaction 批处理 -Batch -对于大量的批 ...