BigInteger Sqrt函数没有收敛

时间:2014-01-08 00:54:56

标签: java biginteger sqrt

我目前正在编写一个函数来查找给定BigInteger的平方根。我的测试文件中的当前数字是250074134890485729738。但是程序在找到sqrt时总是停止在15813732488,其平方是250074135202026670144.我已经复制了这个 来自另一个StackOverflow问题的代码,它停止收敛到相同的数字。它使用牛顿法,而我正在使用巴比伦/苍鹭的方法。

他们的代码:

    public static BigInteger sqrtN(BigInteger in) {
final BigInteger TWO = BigInteger.valueOf(2);
int c;

// Significantly speed-up algorithm by proper select of initial approximation
// As square root has 2 times less digits as original value
// we can start with 2^(length of N1 / 2)
BigInteger n0 = TWO.pow(in.bitLength() / 2);
// Value of approximate value on previous step
BigInteger np = in;

do {
    // next approximation step: n0 = (n0 + in/n0) / 2
    n0 = n0.add(in.divide(n0)).divide(TWO);

    // compare current approximation with previous step
    c = np.compareTo(n0);

    // save value as previous approximation
    np = n0;

    // finish when previous step is equal to current
}  while (c != 0);

return n0;}

我的代码:

    static BigInteger number;
static BigInteger sqrt;

public static void main(String[] args) throws Exception {

    number = new BigInteger(getFile());
    System.out.println("Factoring: \n\n" + number);
    sqrt = sqrt();
    System.out.println("The root is: " + sqrt.toString());
    System.out.println("Test, should equal nearest square at or above original number: " + sqrt.multiply(sqrt).toString() + "\nOriginal number: " + number.toString());
}
public static BigInteger sqrt() {
   BigInteger guess = number.divide(new BigInteger("500"));
   BigInteger TWO = new BigInteger("2");
   BigInteger HUNDRED = new BigInteger("100");
   boolean go = true;
   while (number.subtract((guess.multiply(guess))).abs().compareTo(HUNDRED) ==  1 &&      go){
       BigInteger numOne = guess.divide(TWO);
       BigInteger numTwo = number.divide(guess.multiply(TWO));
       guess = numOne.add(numTwo);
       if (numOne.equals(numTwo))
           go = false;
       System.out.println(guess.toString());
   }


    return guess.add(BigInteger.ONE);

我的输出:

保理:

250074134890485729738
250074134890485979
125037067445243488
62518533722622743
31259266861313370
15629633430660684
7814816715338341
3907408357685169
1953704178874583
976852089501290
488426044878644
244213022695321
122106511859659
61053256953828
30526630524913
15263319358455
7631667871224
3815850319588
1907957927606
954044498302
477153309146
238838702566
119942872245
61013907968
32556274730
20118781556
16274333124
15820250501
15813733820
15813732478
15813732478
The root is: 15813732479
Test, should equal nearest square at or above original number: 250074134917379485441
Original number: 250074134890485729738

一对夫妇注意到:

  1. 写这篇文章时我有几个想法,我试过了。如果事情不匹配,那就是我的错。我做了检查,但我并不完美。
  2. 虽然我很欣赏人们足够慷慨地指出我不同的预先编写的代码/发布他们自己的代码,但这(虽然不是学校工作)对我来说是一次学习经历。请发布如何修复此代码,请不要只发布不同的代码片段。
  3. 答案:这实际上确实有效,原始输入根本不是一个完美的正方形。因此,这完全符合我的目的。感谢所有由于我的无能而浪费时间的人。我已经更改了代码以返回相当于的值(如果Math.sqrt / ceil在BigInts上工作):

        sqrt = Math.Ceil(Math.Sqrt(A_RANDOM_BIGINTEGER_HERE));
    

    我还删除了不必要的变量,并更新了输出以匹配。这两种方法都可以正常工作,尽管第一种方法需要一些代码来捕获非收敛周期,以防任何未来的访问者希望使用它们。

2 个答案:

答案 0 :(得分:2)

15813732478 250074134890485729738的平方根,至少是它的组成部分。根据{{​​1}},真正的平方根是15813732478.149670840219509075711。

有两个问题:

  1. 你循环100次而不是停止收敛。
  2. 您认为calc是错误的,因为您只计算不可分割的部分,因此会出现与sqrt(N)*sqrt(N) = N成比例的错误。

答案 1 :(得分:1)

你的sqrt()函数中有一个compareTo(100)的{​​{1}},其中(我怀疑)总是返回1,即数字的绝对值减去猜测平方总是大于100。

经过测试我看到它是,在你的循环结束时添加这个,你会看到一旦你到达root的差异仍然非常大= 4733709254

此时numOnenumTwo变为相同的值,因此guess对于每个后续迭代也始终相同。

System.out.println("Squaring:" + guess.multiply(guess).toString() +
      "; Substracting: " + number.subtract((guess.multiply(guess))).toString());

您还有c < 100所以如果该比较始终为真,那么它将始终打印100行。