BigDecimal常常被用在我的计算器程序当中,因为它可以实现高精度计算(而且可以满足我对某些数字的好奇心,比如我用它来计算圆周率,看看圆周率后几万位长什么样)。但是我发现好像BigDecimal并没有提供sin,cos,log等函数的计算,也就是说我的计算器就不能把sin,cos计算到小数点后很多位去了。
刚开始时我很天真地用了这种方法来计算”高精度的”三角函数:
String result=BigDecimal.valueOf(Math.cos(a.doubleValue())).toPlainString();
输了个数进去,发现结果是对的!但是这似乎不是高精度的,本质上还是双精度浮点数的计算。于是为了满足我对三角函数值的好奇心,我写了一个用BigDecimal计算三角函数的类。后来因为强迫症,我又把其他的数学函数给加上去了。
目前我的BigMath类支持以下22个函数:
1.三角函数和反三角函数:sin,cos,tan,asin,acos,atan
2.幂及其逆运算:pow,sqrt,cbrt,root,log10,log,ln,exp
3.双曲三角函数和反双曲三角函数:sinh,cosh,tanh,asinh,acosh,atanh
4.弧度角度转换:deg,rad
使用方法:
//用BigMath类的getDefaultBigMath方法获取到BigMath对象,方法需要传入一个PrecisionHolder
BigMath BM=BigMath.getDefaultBigMath(precision);
//上面的precision用于在计算过程中获取计算所需要的精度
PrecisionHolder precision=new PrecisionHolder(){
@Override
public int getPrecision() {
return 50;//返回50,代表结果精确到50位
}
};
然后就可以调用BigMath里的方法了
测试如下:
public class Test0 {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
PrecisionHolder precision=new PrecisionHolder(){
@Override
public int getPrecision() {
System.err.println("请输入精度");
int p=scanner.nextInt();
return p;
}
};
BigMath BM=BigMath.getDefaultBigMath(precision);
while(true){
System.err.println("请输入函数名称.");
System.err.println("支持的函数:sin,cos,tan,asin,acos,atan, pow,sqrt,cbrt,root, log10,log,ln,exp, sinh,cosh,tanh,asinh,acosh,atanh, deg,rad");
String s=scanner.next();
if(s.equals("exit")){
scanner.close();
System.exit(0);
}
if(s.equals("sin")){
System.out.println("结果:"+BM.sin(readDec1(scanner)));
}else if(s.equals("cos")){
System.out.println("结果:"+BM.cos(readDec1(scanner)));
}
//.........省略
else if(s.equals("atanh")){
System.out.println("结果:"+BM.atanh(readDec1(scanner)));
}else if(s.equals("rad")){
System.out.println("结果:"+BM.rad(readDec1(scanner)));
}
System.err.println("=======================================");
}
}
private static BigDecimal readDec1(Scanner scanner){
System.err.println("请输入第一个变量");
return new BigDecimal(scanner.next());
}
private static BigDecimal readDec2(Scanner scanner){
System.err.println("请输入第二个变量");
return new BigDecimal(scanner.next());
}
}
测试结果:
sin:(输入为π/6,即60度角)
pow:(3.73456789的2.58次方)
root:(1234567898520开23.7次方)
sinh和asinh:(这里的输出顺序有点问题,不过结果是正确的)
大部分函数是用泰勒展开或牛顿迭代法计算的,毕竟是BigDecimal,精度高时(大概小数点后100位)计算速度掉的厉害,不过我已经尽量优化减少计算次数来减小耗时了
好吧我承认这似乎没什么用,但既然都做出来了就分享一下吧
附:
由于java的Math类并没有提供asinh,acosh和atanh方法,所以我还写了一个类来补上这个空缺,jar里有个JMath类,提供了这三个静态方法,直接调用就可以了
double d=1.2345;
double result1=JMath.asinh(d);
double result2=JMath.acosh(d);
double result3=JMath.atanh(d);
jar下载地址:https://pan.baidu.com/s/1slbjdUX