使用Java实现的高精度科学计算器

高精度科学计算器
混合运算展示:

在这里插入图片描述

精度展示:

在这里插入图片描述

简介:

可以进行混合运算,混合运算包括加法+,减法-,乘法*,除法/,取余%,左括号(,右括号),根号√,对数log,指数^。

如:输入:(3+2)^2+108/5-10log2+3√64

​ 输出:47.27807190511263678372

理论可以达到无限精度,过高的精度会增加计算时间,需要提前设置精度,即小数点后多少位,默认为32位。

按键功能及使用方法:
按键功能使用方法
CE清空点击该键清空输入输出
清除点击该键清除最后一位输入
Exp指数表示正在更新。。。
+/-符号切换正在更新。。。
+加法可用于混合运算,输入“被加数”,“+”,“加数”后点击“=”计算结果
-减法同加法
*乘法同加法
/除法同加法
Mod取余同加法,按键显示为“Mod”,运算符为”%“
(左括号用于混合运算,限制优先级
)右括号用于混合运算,限制优先级
Rad/Deg规定三角函数计算时的单位按键显示Rad代表使用弧度单位,按键显示Deg代表使用角度单位
2nd切换按键的第二功能点击该按键,三角函数切换为反三角函数,指数和对数功能按键也会进行转换
sin计算正弦函数根据Rad/Deg按键输入对应单位的参数,点击该键直接计算结果
cos计算余弦函数根据Rad/Deg按键输入对应单位的参数,点击该键直接计算结果
tan计算正切函数根据Rad/Deg按键输入对应单位的参数,点击该键直接计算结果
asin计算反正弦函数输入参数,点击该键根据Rad/Deg按键计算对应单位的结果
acos计算反余弦函数输入参数,点击该键根据Rad/Deg按键计算对应单位的结果
atan计算反正切函数输入参数,点击该键根据Rad/Deg按键计算对应单位的结果
2√x平方根输入参数,点击该按键直接计算结果
3√x立方根输入参数,点击该按键直接计算结果
x^2平方输入参数,点击该按键直接计算结果
x^3立方输入参数,点击该按键直接计算结果
x^nn次方先输入x,点击该键,再输入n,点击“=”计算结果,可用于混合运算。
n√xn次根下x先输入n,点击该键,再输入x,点击“=”计算结果,可用于混合运算。
log计算以10为底的对数输入参数,点击该按键直接计算结果。
ylogx以x为底y的对数先输入y,点击该键,再输入x,点击“=”计算结果,可用于混合运算。
ln计算以e为底的对数输入参数,点击该按键直接计算结果。
e^xe的x次方输入参数,点击该按键直接计算结果。
π圆周率点击该键显示圆周率π的数值,该数值精度与设置精度有关。
e自然常数e点击该键显示自然常数e的数值,该数值精度与设置精度有关。
1/x倒数输入参数,点击该键直接计算结果。
运算结果精度说明:

程序中使用Java的BigDecimal类实现高精度,BigDecimal类中自带加法add()、减法subtract()、乘法multiply()、除法**divide()及整数次方pow()**函数。

在上述函数基础上自己实现对数函数log()、指数函数pow()、三角函数sin()cos()tan()arcsin()arccos()arctan()、**arccot()**函数,同样可以达到无限精度。

步骤:

  • 首先实现阶乘函数

    public BigDecimal fac(int n)
    
  • ln(x)的泰勒展开为:
    ln ⁡ ( x ) = ln ⁡ ( 1 + y 1 − y ) = 2 y ( 1 1 + 1 3 y 2 + 1 5 y 4 + 1 7 y 6 + 1 9 y 8 + ⋯   ) \ln (x)=\ln \left(\frac{1+y}{1-y}\right) \quad=2 y\left(\frac{1}{1}+\frac{1}{3} y^{2}+\frac{1}{5} y^{4}+\frac{1}{7} y^{6}+\frac{1}{9} y^{8}+\cdots\right) ln(x)=ln(1y1+y)=2y(11+31y2+51y4+71y6+91y8+)
    其中y = (x - 1) / (x + 1)

    在循环中不断累加,如果当前项的值小于设定精度,默认小于10^-32时退出。

    但该展开式只有在x接近1时收敛比较快,如果计算ln(10)经测试大概耗时3s,完全不能忍。

    接下来通过放缩区间加快速度,已知ln(xy)=ln(x)+ln(y),找一个折中的办法,先将参数x 10倍放缩到[0.5, 5]区间,标记缩放次数为ln10Count,再将参数x 1.1倍缩放到[0.95, 1.05]区间得到x’,标记缩放次数为ln1_1Count,最终结果为ln10Count*ln(10) + ln1_1Count*ln(1.1) + ln(x’),该方法需要提前计算ln(10)与ln(1.1),但计算一次可以永久使用,对于ln(10)转化为10*ln(1.25) + ln(1.073741824)进一步加快速度。

  • y log x即以x为底y的对数可转换为log(y)/log(x)

  • a^x的泰勒展开式为:
    a x = e x ln ⁡ a = 1 + x ln ⁡ a 1 ! + ( x ln ⁡ a ) 2 2 ! + ( x ln ⁡ a ) 3 3 ! + ⋯ a^{x}=e^{x \ln a}=1+\frac{x \ln a}{1 !}+\frac{(x \ln a)^{2}}{2 !}+\frac{(x \ln a)^{3}}{3 !}+\cdots ax=exlna=1+1!xlna+2!(xlna)2+3!(xlna)3+
    其中需要前面实现的ln(x)

  • sin(x)的泰勒展开式为:
    sin ⁡ x = ∑ n = 0 ∞ ( − 1 ) n ( 2 n + 1 ) ! x 2 n + 1 = x − 1 3 ! x 3 + 1 5 ! x 5 − ⋯ + ( − 1 ) n ( 2 n + 1 ) ! x 2 n + 1 + ⋯ \sin x=\sum_{n=0}^{\infty} \frac{(-1)^{n}}{(2 n+1) !} x^{2 n+1}=x-\frac{1}{3 !} x^{3}+\frac{1}{5 !} x^{5}-\cdots+\frac{(-1)^{n}}{(2 n+1) !} x^{2 n+1}+\cdots sinx=n=0(2n+1)!(1)nx2n+1=x3!1x3+5!1x5+(2n+1)!(1)nx2n+1+
    该展开式只能计算[0, PI/2]区间的sin(x)的值,需要先将参数转换到此区间

  • cos(x)同理

  • tan(x) = sin(x)/cos(x)

  • arctan(x)的泰勒展开式为:
    arctan ⁡ x = ∑ n = 0 ∞ ( − 1 ) n 2 n + 1 x 2 n + 1 = x − 1 3 x 3 + 1 5 x 5 + ⋯ + ( − 1 ) n 2 n + 1 x 2 n + 1 + ⋯ \arctan x=\sum_{n=0}^{\infty} \frac{(-1)^{n}}{2 n+1} x^{2 n+1}=x-\frac{1}{3} x^{3}+\frac{1}{5} x^{5}+\cdots+\frac{(-1)^{n}}{2 n+1} x^{2 n+1}+\cdots arctanx=n=02n+1(1)nx2n+1=x31x3+51x5++2n+1(1)nx2n+1+
    x定义域为实数集,但|x|在接近1或大于1的时候收敛速度特别慢

    解决办法:

    1. 使用arctan(-x) = -arctan(x),将参数限制到正实数
    2. 如果x>1,根据arctan(x)=PI/2-arctan(1/x),求arctan(1/x),将参数转换到[0, 1]区间
    3. 但x在接近1时(如0.99)收敛仍然很慢,接下来将参数x限制到[0, 0.5]区间
    4. 如果x>0.5,根据arctan(x)=arctan(y)+arctan((x-y)/(1+xy)),将arctan的参数限制到0.5以下,此处可以选更小的值达到更快的速度
  • arccot(x) = PI/2 - arctan(x)

  • arcsin(x) = arctan(x/sqrt(1-x^2))

  • arccos(x) = PI/2 - arcsin(x)

混合运算实现流程:
  • 使用正则表达式提取输入算式的参数和运算符

    用于匹配的正则表达式:
    在这里插入图片描述

  • 将中缀表达式转为后缀表达式

  • 对后缀表达式进行计算

更新日志:
  • 2020.12.8 20.18

    三角函数仍使用double进行计算,精确到小数点后(16-整数位数)位(如计算atan(80°)=89.28384005452959,即小数位数为16-2位整数位=14位小数位),相当于对double变量表示不了的精度取了个近似值,计算结果不会再出现sin(30°) =0.49999999999999994这种情况。

  • 2020.12.10 16.12

    正则表达式进行了优化,加入正后顾可以正确匹配负数和减法,比如对于“2-3”匹配结果应该为(“2”,“-”,“3”),对于“-2–3”匹配结果应该为(“-2”,“-”,“-3”)。

  • 2020.12.10 16.12

    对数函数仍使用double进行计算,使用与三角函数相同的方法解决精度问题。

  • 2020.12.11 10.46

    结果使用DecimalFormat.format()格式化字符串,三位一体使用“,”分开显示,但输入参数还没有实现,如果要实现的话必须要跟win10计算器一样当参数输入完毕,输入运算符时参数才上移。

  • 2020.12.14 19.07

    使用BigDecimal实现常用数学函数,可以达到无限精度

    输出结果三位一体分隔开,便于阅读,输入暂未实现

待优化功能:
  • 将输入参数和计算结果三位一体使用“,”分隔开,便于阅读,可以使用DecimalFormat.format()函数。
  • 三角函数应该有角度制、弧度制、百分度制(梯度制),暂未实现百分度制。
  • 使用BigDecimal实现对数函数及指数函数求解(log,ln,√,^),这样可以达到任意精度,不再局限于double的精度。
  • 计算前检查算式的合法性,直接用规则检查比较复杂,可以在混合运算解析的过程中使用try和catch捕获异常,对其他非混合运算算式可直接检查。比如检查反三角函数的输入参数范围可以直接用规则检查,检查阶乘的参数是不是整数二者都可以。

现对数函数及指数函数求解(log,ln,√,^),这样可以达到任意精度,不再局限于double的精度。~~

  • 计算前检查算式的合法性,直接用规则检查比较复杂,可以在混合运算解析的过程中使用try和catch捕获异常,对其他非混合运算算式可直接检查。比如检查反三角函数的输入参数范围可以直接用规则检查,检查阶乘的参数是不是整数二者都可以。

这个计算器也是匆匆赶时间完成的,再加上不可能考虑到所有输入情况,没有对错误的输入进行提示,其中肯定存在不少问题,项目地址在下面,其中包括4个java文件,CalculatorHMI实现计算器的图形界面及按键的事件处理,修改其中的accuracy变量可以改变精度,也就是结果精确到小数点后多少位,默认为32位,更高的位数也可以,但计算时间也会加长。BigDecimalMath就是用泰勒公式重写的Math库中的函数,MixedOperation实现混合运算,Main文件中就是主函数,是整个工程的入口。当然电脑上必须有jre也就是java运行环境才可以运行。

项目视频
github地址

------故里草木深------

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值