java大数类解决黄金连分数

java大数类有BigInteger大整数和BigDecimal大浮点数.
具体方法,参考API,下面例题中使用BigDecimal

题目描述
标题: 黄金连分数
黄金分割数0.61803… 是个无理数,这个常数十分重要,在许多工程问题中会出现。有时需要把这个数字求得很精确。
对于某些精密工程,常数的精度很重要。也许你听说过哈勃太空望远镜,它首次升空后就发现了一处人工加工错误,对那样一个庞然大物,其实只是镜面加工时有比头发丝还细许多倍的一处错误而已,却使它成了“近视眼”!!
言归正传,我们如何求得黄金分割数的尽可能精确的值呢?有许多方法。
比较简单的一种是用连分数:

              1
黄金数 = ---------------------
                    1
         1 + -----------------
                      1
             1 + -------------
                        1
                 1 + ---------
                      1 + ...

这个连分数计算的“层数”越多,它的值越接近黄金分割数。
请你利用这一特性,求出黄金分割数的足够精确值,要求四舍五入到小数点后100位。
小数点后3位的值为:0.618
小数点后4位的值为:0.6180
小数点后5位的值为:0.61803
小数点后7位的值为:0.6180340
(注意尾部的0,不能忽略)
你的任务是:写出精确到小数点后100位精度的黄金分割值。
注意:尾数的四舍五入! 尾数是0也要保留!
显然答案是一个小数,其小数点后有100位数字,请通过浏览器直接提交该数字。
注意:不要提交解答过程,或其它辅助说明类的内容。

思路:
这是一个很明显的递归程序,所以第一个想法就是递归.递归设计也很简单,只要递归次数大于一定值,那么得到的结果就会相对精确很多

import java.math.BigDecimal;

public class Test {
    public static void main(String[] args) {
        System.out.println(f(0));
    }

    public static BigDecimal f(int step) {
        if (step >= 200)//递归200次
            return BigDecimal.ONE;
            //除法要设置精度的
        return BigDecimal.ONE.divide(BigDecimal.ONE.add(f(step + 1)), 100 ,BigDecimal.ROUND_HALF_DOWN);
    }
}

另一种想法就是黄金比例等于(根号5-1)/2,如果得到5的开方的高精度值也是可以计算出来黄金比例的
得到一个数的高精度的开方,就可以使用牛顿的迭代公式x = 0.5*(x+a/x)
其中a为要开方的数,x为开方后的数,可以给x一个相近的初始值,然后迭代次数增多后,x无限接近于a的开方.也就是精确值.

/** * 指定精度计算平方根 * @param a 要计算平方根的数 * @param b 该平方根近似值,例如2的平方根近似值可以指定1,用来减少循环次数 * @param scale 指定小数位 * @return */
    private static String sqrt(int a,int b,int scale){
        StringBuilder builder = new StringBuilder();
        builder.append("0.");
        for (int i = 0; i < scale; i++) {
            builder.append("0");
        }
        builder.append("1");

        BigDecimal aBigDecimal = new BigDecimal(a);
        BigDecimal dif = new BigDecimal(builder.toString());//指定精度
        BigDecimal x2 = new BigDecimal(0);//用于存储每次计算后的x值
        BigDecimal x1 = new BigDecimal(b);//计算前x的值
        BigDecimal temp = new BigDecimal(0.5);///常量0.5
        while(true){
            //模拟公式
            x2 = temp.multiply(x1.add(aBigDecimal.divide(x1,102,BigDecimal.ROUND_DOWN)));
            //判断精度是否达到指定精度,判断方法是两次结果相差是否小于指定精度
            if (x2.compareTo(x1) == 1) {
                if (x2.subtract(x1).compareTo(dif) == -1 ) {
                    break;
                }
            }else {
                if (x1.subtract(x2).compareTo(dif) == -1 ) {
                    break;
                }
            }
            x1=x2;
        }

        x1 = x1.subtract(BigDecimal.ONE).divide(new BigDecimal(2));
        x1 = x1.setScale(scale, BigDecimal.ROUND_HALF_DOWN);//设置保留小数位
        return x1.toString();
    }

有意思的是这个计算在C和java下是有误差的
java 0.6180339887498948482045868343656381177203091798057628621354486227052604628189024497080360587685914626

C++
0.61803398874989484819719595255086212205106635745185384537231876012295828219717843480838632961

你可能感兴趣的:(java)