说起编程中的高精度数值,我第一反应就是double类型了。的确,double阶码11位,尾数52位,几乎能应对任何苛刻的要求......然而,当我天真地尝试用double来算泰勒展开式的函数值,离散代数的狰狞性瞬间完全暴露眼前。

我不是数学出身,也并不关心那些奇异的函数形式。我只是想推导一个物理系统的冲击响应函数。那个函数没法求得解析解,我只好用皮卡迭代法求泰勒级数式。经过一番挣扎,级数通项终于确定了,但是函数的绘图却成了隐藏难题。

函数的形式:

\[f(x)={\sum_{n=1}^{\infty}{\frac{(-1)^n*2n}{2^n*(n!)^2}*x^{2n-2}}}
\]

函数形似一个衰减的正弦振荡,本应该长这样:

但是实际上泰勒级数绘制出来长这样:

甚至这样:

崩溃了,仔细检查原因,发现最后几项级数取值超过\(10^{300}\),换言之double活生生撑爆了。。。

接下来的几天我在网上查找了半天提高浮点数长度(精度)的方法,但是收获甚微。python的numpy好似有float_128,但其实是80位扩展double。c语言倒是找到了诸如mpfr之类的4精度数计算包,但是这也是治标不治本。

由于我用java做科学计算的习惯(奇异癖好),我决定用java写一个任意精度浮点数计算工具(类)。

LFloat类(large float)原理:

由于电脑显然不能存储太长的数字,我决定用long数组存储浮点数的小数部分。并且,考虑到乘法的计算问题,如果两个long类型的整数直接相乘,最多会有接近64位(二进制)的得数由于long溢出而丢弃,从而达不到准确计算的目的。最后,我只能妥协,每一个long储存32位(二进制)小数部分。

这样的好处在于对于加减乘法,0-31位的进位部分会保存在31-63位处,从而方便后续处理。对于除法,我没有采用较为高效的方法,而只是朴素的逐位作差实现。

另一个难点是数字的输入与输出。由于精度变态,double输入显然不太合适(除了极个别数,一般的double数都是做了近似截断的,不会太准确)。为此只能输入String字符串,再自定义parse函数来读取、存储数字。对于显示,则采取读取数字的逆运算,经过一系列的2-10转换最终输出。

输入输出还有一个难点,即指数的转化。输入、输出的数字都由科学计数法表示,动辄“1E+1000”之类的天文数字。为了便于转化,所有数字输入时都先取log,求出阶码,再用exp函数算出小数部分的二进制数。

成果:

  • 实现了任意指定精度的浮点数的运算,并且阶码有62位,最大能表示\(10^{10^{18}}\)这等天文数字!
  • 浮点数运算近似符合IEEE 754标准,处理舍入方面直接截断,而没有向偶数取整(其实不太需要,感觉精度差了就多加几位精度呗~)。

一些测试,以及计算\(\pi\)的数值到400位:

代码:

见我的github页面,测试代码也在里面,注释较为详细。

结束语:

经过千辛万苦终于写成了较为高效的高精度浮点数计算代码,编写期间排除bug无数,希望这个工具对大家有所帮助。

p.s.如果有人发现了什么bug(一定有的),或者提出什么可以改进的地方,欢迎留言~

Java 高精度浮点数计算工具的更多相关文章

  1. java第二周的学习知识4(对原码,补码,反码和java中浮点数计算不准确的总结)

    原码:一个正数,转换为二进制位就是这个正数的原码.负数的绝对值转换成二进制位然后在高位补1就是这个负数的原码. 但是原码有几个缺点,零分两种 +0 和 -0 .很奇怪是吧!还有,在进行不同符号的加法运 ...

  2. JAVA简单精确计算工具类

    1 public class ArithUtil { 2 3 // 默认除法运算精度 4 private static final int DEF_DIV_SCALE = 10; 5 6 privat ...

  3. 计算价格, java中浮点数精度丢失的解决方案

    计算价格, java中浮点数精度丢失的解决方案

  4. java精确计算工具类

    java精确计算工具类 import java.math.BigDecimal; import java.math.RoundingMode; import java.math.BigDecimal; ...

  5. 学以致用:手把手教你撸一个工具库并打包发布,顺便解决JS浮点数计算精度问题

    本文讲解的是怎么实现一个工具库并打包发布到npm给大家使用.本文实现的工具是一个分数计算器,大家考虑如下情况: \[ \sqrt{(((\frac{1}{3}+3.5)*\frac{2}{9}-\fr ...

  6. java中浮点数的比较(double, float)(转)

    问题的提出:如果我们编译运行下面这个程序会看到什么? public static void main(String args[]){ System.out.println(0.05+0.01); Sy ...

  7. 最全的Java操作Redis的工具类,使用StringRedisTemplate实现,封装了对Redis五种基本类型的各种操作!

    转载自:https://github.com/whvcse/RedisUtil 代码 ProtoStuffSerializerUtil.java import java.io.ByteArrayInp ...

  8. 常用 Java 静态代码分析工具的分析与比较

    常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...

  9. [原创]Java静态代码检查工具介绍

    [原创]Java静态代码检查工具介绍 一  什么是静态代码检查? 静态代码分析是指无需运行被测代码,仅通过分析或检查源程序的语法.结构.过程.接口等来检查程序的正确性,找出代码隐藏的错误和缺陷,如参数 ...

随机推荐

  1. 深入剖析 ConcurrentHashMap

    自建博客地址:https://bytelife.net,欢迎访问! 本文为博客自动同步文章,为了更好的阅读体验,建议您移步至我的博客 本文作者: Jeffrey 本文链接: https://bytel ...

  2. 1.3 PHP+MYSQL+APACHE配置(序)

    本节对服务器端web服务进行配置.事实上,对于配置这个环境(WAMP)网上还是有很多教程的,大家可以通过网上的教程完成配置,也不必拘泥于本文.甚至网上有免费的服务器端软件可以选择,比如著名的phpst ...

  3. .NET测试断言工具Shouldly

    .NET测试断言工具Shouldly .NET测试 Shouldly在GitHub的开源地址:https://github.com/shouldly/shouldly Shouldly的官方文档:ht ...

  4. 图解CyclicBarrier运动员接力赛

    图解游戏规则 大家都知道运动员短跑接力赛,今天我们并不是讲接力赛,我们讲"接力协作赛",需要我们重新定义下游戏规则:如下图所示 现在有运动员A,B,先定义游戏规则:赛道目前是300 ...

  5. 【Java进阶面试系列之一】哥们,你们的系统架构中为什么要引入消息中间件?

    转: [Java进阶面试系列之一]哥们,你们的系统架构中为什么要引入消息中间件? **这篇文章开始,我们把消息中间件这块高频的面试题给大家说一下,也会涵盖一些MQ中间件常见的技术问题. 这里大家可以关 ...

  6. OpenGL中的坐标系统详细概括:包括Z缓冲

    一: 首先就是关于几个坐标系统的概括: 局部坐标是对象相对于局部原点的坐标,也是物体起始的坐标. 下一步是将局部坐标变换为世界空间坐标,世界空间坐标是处于一个更大的空间范围的.这些坐标相对于世界的全局 ...

  7. java将一个list转换成一个String,中间用分隔符隔开

    List sn=[123,1231,1231,231] sn.toString();//[123,1231,1231,231] sn.join(',').toString();//123,1231,1 ...

  8. 内省详解(Introspector/BeanInfo/MethodDescriptor/PropertyDescriptor)

    内省(Introspector)概念 ​ 内省Introspector 是Java提供的操作 JavaBean 的 API,用来访问某个属性的 getter/setter 方法.对于一个标准的 Jav ...

  9. Java 树结构的基础部分(二)

    1 顺序存储二叉树 1.1 顺序存储二叉树的概念  基本说明 从数据存储来看,数组存储方式和树的存储方式可以相互转换,即数组可以转换成树,树也可以转换成数组, 看下面的示意图.  要求: 1) 右 ...

  10. java重写toString()方法

    toString()方法是Object类的方法,调用toString()会返回对象的描述信息. 1)为什么重写toString()方法呢? 如果不重写,直接调用Object类的toString()方法 ...