【问题标题】:Find The Millionth Fibonacci in Java在 Java 中找到第百万个斐波那契
【发布时间】:2016-01-25 02:45:06
【问题描述】:

在斐波那契数列中,每一项都是前两项之和。

fibonacci(1) == 1, fibonacci(0) == 0; 
fibonacci(2) = fibonacci(1) + fibonacci(0);
...

在网上搜索后,我找到了这个算法来解决:

这是我的代码:

import java.math.BigInteger;

public class Fibonacci {
    public static BigInteger fib(BigInteger n) {
        double p = (1 + Math.sqrt(5)) / 2;
        double q = (1 - Math.sqrt(5) / 2;
        BigInteger result = BigInteger.ZERO;
        result = ( Math.pow(p, n) - Math.pow(q, n) ) / Math.sqrt(5); //error
        return result;
    }
}

如何解决这个错误,我要参数是BigInteger,不是Integer,返回的数字也是BigInteger。

【问题讨论】:

  • 无重复,请从我的问题再考虑。
  • How to solve that error - 哪个那个错误?回避怎么办?您首先要实现什么目标?
  • 我的代码中的错误,Math.pow(parameter 1, parameter 2)
  • 我很好奇你在哪里找到了斐波那契数列的公式。我从来没有见过这样表达的。有链接吗?

标签: java algorithm fibonacci


【解决方案1】:

您需要使用BigDecimal#pow(),而不是Math.pow()

因为Math.pow() 返回double,但如果pn 太大,则会引发原始溢出错误。

BigDecimal bp = new BigDecimal(p);
BigDecimal bq = new BigDecimal(q);

BigDecimal result = bp.pow(n); // n must be in the range 0 through 999999999, inclusive. ZERO. 

现在result 得到p^nBigDecimal。希望您了解BigDecimal 的计算。

【讨论】:

  • 这是:BigInteger.ZERO.pow(n)?但是怎么把p和q放进去呢?
  • 我为你写了一些代码,如果对你有帮助,请告诉我。
  • BigDecimal 结果 = bp.pow(n); //n 出错,因为 n 是 BigInteger
  • 因为方法pow(int exponent)将param作为int
  • 我知道,但是我需要我的函数中的参数是BigInteger,怎么办?
【解决方案2】:

Big 数字不会覆盖 Java 中的标准数学运算符。这些只是对象。所以你必须把它们当作对象来处理。

public static BigInteger fib(int n) {
    BigDecimal phi = new BigDecimal((1 + Math.sqrt(5)) / 2).pow(n);
    BigDecimal phi_ = new BigDecimal((1 - Math.sqrt(5)) / 2).pow(n);
    BigDecimal divider = new BigDecimal(Math.sqrt(5));
    BigDecimal result = phi.subtract(phi_).divide(divider);
    return result.toBigInteger();
}

更新:

正如@Gassa所说,上述方法会累积错误,因为

BigDecimaldouble 初始化,而 double 的精度为 只有 15 位小数

但我们需要更多。

所以我们可以对来自hereBigDecimal使用sqrt方法:

public static BigInteger fib(int n) {
    BigDecimal one = new BigDecimal(1);
    BigDecimal sqrtFive = bigSqrt(new BigDecimal(5));
    BigDecimal two = new BigDecimal(2);

    BigDecimal phi = one.add(sqrtFive).divide(two, RoundingMode.HALF_DOWN).pow(n);
    BigDecimal phi_ = one.subtract(sqrtFive).divide(two, RoundingMode.HALF_DOWN).pow(n);

    BigDecimal result = phi.subtract(phi_).divide(sqrtFive, RoundingMode.HALF_DOWN);

    return result.toBigInteger();
}

private static final BigDecimal SQRT_DIG = new BigDecimal(150);
private static final BigDecimal SQRT_PRE = new BigDecimal(10).pow(SQRT_DIG.intValue());

/**
 * Private utility method used to compute the square root of a BigDecimal.
 *
 * @author Luciano Culacciatti
 * @url http://www.codeproject.com/Tips/257031/Implementing-SqrtRoot-in-BigDecimal
 */
private static BigDecimal sqrtNewtonRaphson  (BigDecimal c, BigDecimal xn, BigDecimal precision){
    BigDecimal fx = xn.pow(2).add(c.negate());
    BigDecimal fpx = xn.multiply(new BigDecimal(2));
    BigDecimal xn1 = fx.divide(fpx,2*SQRT_DIG.intValue(), RoundingMode.HALF_DOWN);
    xn1 = xn.add(xn1.negate());
    BigDecimal currentSquare = xn1.pow(2);
    BigDecimal currentPrecision = currentSquare.subtract(c);
    currentPrecision = currentPrecision.abs();
    if (currentPrecision.compareTo(precision) <= -1){
        return xn1;
    }
    return sqrtNewtonRaphson(c, xn1, precision);
}

/**
 * Uses Newton Raphson to compute the square root of a BigDecimal.
 *
 * @author Luciano Culacciatti
 * @url http://www.codeproject.com/Tips/257031/Implementing-SqrtRoot-in-BigDecimal
 */
public static BigDecimal bigSqrt(BigDecimal c){
    return sqrtNewtonRaphson(c,new BigDecimal(1),new BigDecimal(1).divide(SQRT_PRE));
}

【讨论】:

  • @Gassa,非常感谢,我真的忘记了double 的准确性。我更新了我的答案。
猜你喜欢
  • 2016-02-17
  • 2019-06-26
  • 1970-01-01
  • 2012-10-12
  • 2021-09-03
  • 1970-01-01
  • 2022-12-10
  • 2014-02-22
  • 1970-01-01
相关资源
最近更新 更多