java BigDecimal实现高精度数学函数计算

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

猜你喜欢

转载自blog.csdn.net/jtyj55454/article/details/76718455