有没有办法避免在进行令人难以置信的大数字时使用BigIntegers?

时间:2016-09-10 05:18:23

标签: java algorithm math biginteger

我正在尝试编写一个程序,该程序可以从用户那里获得有关斐波纳契数的输入,并使用该数字来获得该斐波纳契数的索引。

所以我在网上搜索了斐波那契数字,我只找到一个可用的公式,即a(n) = [ Phi*n - (phi)*n ]/Sqrt[5]。 n是斐波那契数的指数,a(n)是数。因此,我使用此公式制作如下程序:

/** Fibonacci Sequence
  * Tony
  */
import java.util.Scanner;
import java.math.*;
public class Solution67 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int times = sc.nextInt();
    for (int i = 0; i < times; i++) {
//    String fNumstr = sc.next();
//    BigInteger fNum = new BigInteger(fNumstr);
      int fNum = sc.nextInt();
      double pPhi = (1 + Math.sqrt(5))/2;
      double pphi = (1 - Math.sqrt(5))/2;
      int n = 0;
      while ((int)(Math.pow(pPhi, n) - Math.pow(pphi, n)) != (int)(fNum * Math.sqrt(5))) 
        //^ how to make Math.pow(pPhi, n) a big Integer
      {
        n ++;
      }
      System.out.print(n + " ");
    }
  }
}

所以它适用于小数字。但是,如果我使用像86168291600238450732788312165664788095941068326060883324529903470149056115823592713458328176574447204501这样令人难以置信的大数字,那么它会给我一个错误信息,我知道为什么。所以我想也许我应该使用BigInteger和BigDecimal而不是int和double来解决这个问题。但不知怎的,我觉得我制作这个程序的方法看起来有点过于复杂和低效。因为我必须让我的计算机尝试从0到实际索引的所有数字,我几乎不能使用BigInteger和BigDecimal,而不会产生不准确的数字,并且失败了。所以我可能想问一下,在开始时是否有更好的方法来做这件事,或者我的方式是唯一的方法,我只需要使用BigInteger和BigDecimal? THX!

您好我在这里查看了所有答案和回复。有些我还没有完全理解。但我认为我正在努力的是,我觉得我解决它的方式太复杂了,我想也许我试图让这个程序完全错误的方向。所以我只是尝试找到最简单的算法来完成这项任务。

我可能仍会使用BigInteger和BigDecimal来解决这个问题。我之前对准确的平方根感到困惑,但现在我认为因为每个值都不是那么接近所以我可能会使用舍入值,它可能仍然可以工作。

@PeterLawrey我不明白If you are calculating every number adding the two previous numbers is the fastest, most accurate and simplest way to do it.你的意思,但我觉得这似乎是一种有趣的简单方法来完成这项工作。你能解释一下吗?

所以我使用递归函数getFN完成了我的代码,从参数n得到Fibonacci数f(n)。代码如下:

/** Fibonacci Sequence
  * Tony
  */
import java.util.Scanner;
import java.math.*;
public class Solution67 {
  public static BigInteger getFN (int n) {
    BigInteger one = new BigInteger("1");
    BigInteger zero = new BigInteger("0");
    if (n == 1) {
      return zero;
    }
    else if (n == 2) {
      return one;
    }

    else {
      BigInteger fn = getFN(n-1).add(getFN(n-2));
      return fn;
    }
  }



  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int times = sc.nextInt();
    for (int i = 0; i < times; i++) {
      String fNumstr = sc.next();
      BigInteger fNum = new BigInteger(fNumstr);
      int n = 1;
      while (!fNum.equals(getFN(n))) {
        n ++;
      }
      System.out.print(n-1 + " ");


    }
  }
}

并且它有效,但正如我预测的这种暴力方式(尝试每一个n直到得到正确的n)是非常低效的。当我用非常大的数字运行这个程序时,它只是继续处理。 (我确信这个程序有效,因为我尝试了一些小编号。)

1 个答案:

答案 0 :(得分:2)

您可以通过使用字符串或StringBuilder来避免使用BigInteger。这并不像听起来那么疯狂,因为BigInteger.toString对于大数字而言相当昂贵,并且添加相当容易实现。

如果您正在计算每个数字,那么添加前两个数字是最快,最准确和最简单的方法。您可以将BigInteger用于较大的值。

注意:最昂贵的部分是使用一些智能打印数字为O(n ^ 2)或更好,其中n是数字位数。

你可以在这个公式中使用BigDecimal,但这只有在你想随机选择一个大值或想要一个小数斐波纳契值时才有意义。