簡體   English   中英

如何找到 Java BigInteger 的平方根?

[英]How can I find the Square Root of a Java BigInteger?

是否有一個庫可以找到 BigInteger 的平方根? 我希望它離線計算 - 只計算一次,而不是在任何循環內。 因此,即使是計算量大的解決方案也可以。

我不想找到一些算法並實現。 一個現成的解決方案將是完美的。

只是為了好玩:

public static BigInteger sqrt(BigInteger x) {
    BigInteger div = BigInteger.ZERO.setBit(x.bitLength()/2);
    BigInteger div2 = div;
    // Loop until we hit the same value twice in a row, or wind
    // up alternating.
    for(;;) {
        BigInteger y = div.add(x.divide(div)).shiftRight(1);
        if (y.equals(div) || y.equals(div2))
            return y;
        div2 = div;
        div = y;
    }
}

我知道您的問題沒有圖書館解決方案。 您必須從某處導入外部庫解決方案。 我在下面給您的內容比獲取外部庫要簡單。

您可以在具有兩個靜態方法的類中創建自己的外部庫解決方案,如下所示,並將其添加到您的外部庫集合中。 這些方法不需要是實例方法,因此它們是靜態的,而且方便的是,您不必實例化類來使用它們。 整數平方根的范數是一個下限值(即小於或等於平方根的最大整數),所以你可能只需要下面這個類中的一個靜態方法,下限方法,下限值可以選擇忽略上限(即大於或等於平方根的最小整數)方法版本。 現在,它們位於默認包中,但您可以添加一個包語句,將它們放入您認為方便的任何包中。

這些方法非常簡單,迭代非常非常快地收斂到最接近的整數答案。 如果你試圖給他們一個否定的參數,他們會拋出一個 IllegalArgumentException。 您可以將異常更改為另一個異常,但必須確保否定參數會引發某種異常或至少不嘗試計算。 負數的整數平方根不存在,因為我們不在虛數領域。

這些來自眾所周知的簡單迭代整數平方根算法,這些算法已在手工計算中使用了幾個世紀。 它的工作原理是平均高估和低估以收斂到更好的估計。 這可以重復直到估計與期望的一樣接近。

它們基於 y1 = ((x/y0) + y0) / 2 收斂到最大整數 yn,其中 yn * yn <= x。

這將為您提供 x 的 BigInteger 平方根 y 的下限值,其中 y * y <= x 和 (y + 1) * (y + 1) > x。

改編可以為您提供 BigInteger 平方根 y 的上限值,其中 y * y >= x 並且 (y - 1) * (y - 1) < x

這兩種方法都經過測試並有效。 他們在這里:

import java.math.BigInteger;

public class BigIntSqRoot {

public static BigInteger bigIntSqRootFloor(BigInteger x)
        throws IllegalArgumentException {
    if (x.compareTo(BigInteger.ZERO) < 0) {
        throw new IllegalArgumentException("Negative argument.");
    }
    // square roots of 0 and 1 are trivial and
    // y == 0 will cause a divide-by-zero exception
    if (x .equals(BigInteger.ZERO) || x.equals(BigInteger.ONE)) {
        return x;
    } // end if
    BigInteger two = BigInteger.valueOf(2L);
    BigInteger y;
    // starting with y = x / 2 avoids magnitude issues with x squared
    for (y = x.divide(two);
            y.compareTo(x.divide(y)) > 0;
            y = ((x.divide(y)).add(y)).divide(two));
    return y;
} // end bigIntSqRootFloor

public static BigInteger bigIntSqRootCeil(BigInteger x)
        throws IllegalArgumentException {
    if (x.compareTo(BigInteger.ZERO) < 0) {
        throw new IllegalArgumentException("Negative argument.");
    }
    // square roots of 0 and 1 are trivial and
    // y == 0 will cause a divide-by-zero exception
    if (x == BigInteger.ZERO || x == BigInteger.ONE) {
        return x;
    } // end if
    BigInteger two = BigInteger.valueOf(2L);
    BigInteger y;
    // starting with y = x / 2 avoids magnitude issues with x squared
    for (y = x.divide(two);
            y.compareTo(x.divide(y)) > 0;
            y = ((x.divide(y)).add(y)).divide(two));
    if (x.compareTo(y.multiply(y)) == 0) {
        return y;
    } else {
        return y.add(BigInteger.ONE);
    }
} // end bigIntSqRootCeil
} // end class bigIntSqRoot

奇怪的是,之前沒有人提到過它,但是在 Java 9 中,你在 BigInteger 中有 sqrt,所以你可以這樣使用它:

BigInteger nine = BigInteger.valueOf(9);
BigInteger three = nine.sqrt();

https://docs.oracle.com/javase/9​​/docs/api/java/math/BigInteger.html#sqrt--


編輯-1

補充一點,這個函數還有另一種風格,除了平方根之外,還返回余數

 sqrtAndRemainder() BigInteger[] Returns an array of two BigIntegers containing the integer square root s of this and its remainder this - s*s, respectively.

我無法驗證它們的准確性,但在谷歌搜索時有幾個本土解決方案。 其中最好的似乎是這個: http : //www.merriampark.com/bigsqrt.htm

還可以嘗試 Apache commons Math 項目(一旦 Apache 從 JCP 博客文章的轟炸中恢復過來)。

正如Jigar所說,牛頓的迭代非常容易理解和實現。 我會留給其他人來決定它是否是最有效的算法來找到一個數字的平方根。

通過遞歸,它可以在大約兩行中完成。

private static BigInteger newtonIteration(BigInteger n, BigInteger x0)
{
    final BigInteger x1 = n.divide(x0).add(x0).shiftRight(1);
    return x0.equals(x1)||x0.equals(x1.subtract(BigInteger.ONE)) ? x0 : newtonIteration(n, x1);
}

其中n是我們想要求平方根的數字, x0是前一次調用的數字,當從另一個方法啟動第一次調用時,它始終為 1。 所以最好,你也會用這樣的東西來補充它;

public static BigInteger sqrt(final BigInteger number)
{
    if(number.signum() == -1)
        throw new ArithmeticException("We can only calculate the square root of positive numbers.");
    return newtonIteration(number, BigInteger.ONE);
}

對於初步猜測,我將使用Math.sqrt(bi.doubleValue())並且您可以使用已經建議的鏈接使答案更准確。

我需要有 BigIntegers 的平方根來實現二次篩。 我在這里使用了一些解決方案,但迄今為止絕對最快和最好的解決方案來自 Google Guava 的 BigInteger 庫。

文檔可以在這里找到。

另一種方法,它很輕。 在速度方面,Mantono 使用牛頓法的答案在某些情況下可能更可取。

這是我的方法...

public static BigInteger sqrt(BigInteger n) {
    BigInteger a = BigInteger.ONE;
    BigInteger b = n.shiftRight(1).add(new BigInteger("2")); // (n >> 1) + 2 (ensure 0 doesn't show up)
    while (b.compareTo(a) >= 0) {
        BigInteger mid = a.add(b).shiftRight(1); // (a+b) >> 1
        if (mid.multiply(mid).compareTo(n) > 0)
            b = mid.subtract(BigInteger.ONE);
        else
            a = mid.add(BigInteger.ONE);
    }
    return a.subtract(BigInteger.ONE);
}

這是我發現的最好(也是最短)的工作解決方案

http://faruk.akgul.org/blog/javas-missing-algorithm-biginteger-sqrt/

這是代碼:

  public static BigInteger sqrt(BigInteger n) {
    BigInteger a = BigInteger.ONE;
    BigInteger b = new BigInteger(n.shiftRight(5).add(new BigInteger("8")).toString());
    while(b.compareTo(a) >= 0) {
      BigInteger mid = new BigInteger(a.add(b).shiftRight(1).toString());
      if(mid.multiply(mid).compareTo(n) > 0) b = mid.subtract(BigInteger.ONE);
      else a = mid.add(BigInteger.ONE);
    }
    return a.subtract(BigInteger.ONE);
  }

我已經測試過它並且它工作正常(而且看起來很快)

簡化了Jim 的回答並提高了性能。

public class BigIntSqRoot {
    private static BigInteger two = BigInteger.valueOf(2L);

    public static BigInteger bigIntSqRootFloor(BigInteger x)
            throws IllegalArgumentException {
        if (checkTrivial(x)) {
            return x;
        }
        if (x.bitLength() < 64) { // Can be cast to long
            double sqrt = Math.sqrt(x.longValue());
            return BigInteger.valueOf(Math.round(sqrt));
        }
        // starting with y = x / 2 avoids magnitude issues with x squared
        BigInteger y = x.divide(two);
        BigInteger value = x.divide(y);
        while (y.compareTo(value) > 0) {
            y = value.add(y).divide(two);
            value = x.divide(y);
        }
        return y;
    }

    public static BigInteger bigIntSqRootCeil(BigInteger x)
            throws IllegalArgumentException {
        BigInteger y = bigIntSqRootFloor(x);
        if (x.compareTo(y.multiply(y)) == 0) {
            return y;
        }
        return y.add(BigInteger.ONE);
    }

    private static boolean checkTrivial(BigInteger x) {
        if (x == null) {
            throw new NullPointerException("x can't be null");
        }
        if (x.compareTo(BigInteger.ZERO) < 0) {
            throw new IllegalArgumentException("Negative argument.");
        }

        // square roots of 0 and 1 are trivial and
        // y == 0 will cause a divide-by-zero exception
        if (x.equals(BigInteger.ZERO) || x.equals(BigInteger.ONE)) {
            return true;
        } // end if
        return false;
    }
}
    BigDecimal BDtwo = new BigDecimal("2");
    BigDecimal BDtol = new BigDecimal(".000000001");    
private BigDecimal bigIntSQRT(BigDecimal lNew, BigDecimal lOld, BigDecimal n) {
        lNew = lOld.add(n.divide(lOld, 9, BigDecimal.ROUND_FLOOR)).divide(BDtwo, 9, BigDecimal.ROUND_FLOOR);
        if (lOld.subtract(lNew).abs().compareTo(BDtol) == 1) {
            lNew = bigIntSQRT(lNew, lNew, n);
        }
    return lNew;
}

我剛剛在解決這個問題,並成功地用 Java 編寫了一個遞歸平方根查找器。 您可以將BDtol更改為您想要的任何內容,但這運行得相當快,結果給了我以下示例:

原號14678391142336457674309253729933335637692683931121739087571335401020890062659255388687650825432051051

SQRT --> 383123885216472214589586756787577295328224028242477055.000000000

然后確認146783911423364576743092537299333563769268393112173908757133540102089006265925538868650825403000000505040000000000000005

更新(2018 年 7 月 23 日):此技術不適用於更大的值。 在下面發布了基於二進制搜索的不同技術。


我正在研究因式分解並最終寫了這篇文章。

package com.example.so.math;

import java.math.BigInteger;

/**
 * 
 * <p>https://stackoverflow.com/questions/4407839/how-can-i-find-the-square-root-of-a-java-biginteger</p>
 * @author Ravindra
 * @since 06August2017
 *
 */
public class BigIntegerSquareRoot {

    public static void main(String[] args) {

        int[] values = {5,11,25,31,36,42,49,64,100,121};

        for (int i : values) {
            BigInteger result = handleSquareRoot(BigInteger.valueOf(i));
            System.out.println(i+":"+result);
        }


    }


    private static BigInteger handleSquareRoot(BigInteger modulus) {

        int MAX_LOOP_COUNT = 100; // arbitrary for now.. but needs to be proportional to sqrt(modulus)

        BigInteger result = null;

        if( modulus.equals(BigInteger.ONE) ) {
            result = BigInteger.ONE;
            return result;
        }

        for(int i=2;i<MAX_LOOP_COUNT && i<modulus.intValue();i++) { // base-values can be list of primes...
            //System.out.println("i"+i);
            BigInteger bigIntegerBaseTemp = BigInteger.valueOf(i);
            BigInteger bigIntegerRemainderTemp = bigIntegerBaseTemp.modPow(modulus, modulus);
            BigInteger bigIntegerRemainderSubtractedByBase = bigIntegerRemainderTemp.subtract(bigIntegerBaseTemp);
            BigInteger bigIntegerRemainderSubtractedByBaseFinal = bigIntegerRemainderSubtractedByBase;

            BigInteger resultTemp = null;
            if(bigIntegerRemainderSubtractedByBase.signum() == -1 || bigIntegerRemainderSubtractedByBase.signum() == 1) {

                bigIntegerRemainderSubtractedByBaseFinal = bigIntegerRemainderSubtractedByBase.add(modulus);
                resultTemp = bigIntegerRemainderSubtractedByBaseFinal.gcd(modulus);

            } else if(bigIntegerRemainderSubtractedByBase.signum() == 0) {
                resultTemp = bigIntegerBaseTemp.gcd(modulus);
            }

            if( resultTemp.multiply(resultTemp).equals(modulus) ) {
                System.out.println("Found square root for modulus :"+modulus);
                result = resultTemp;
                break;
            }
        }

        return result;
    }


}

該方法可以這樣形象化:

整數的冪模數羅 - N

希望這可以幫助!

這是我想出的一個快速方法。 有關更多詳細信息,請參見此處

// A fast square root by Ryan Scott White. 
public static BigInteger NewtonPlusSqrt(BigInteger x) {
    if (x.compareTo(BigInteger.valueOf(144838757784765629L)) < 0) {
        long xAsLong = x.longValue();
        long vInt = (long)Math.sqrt(xAsLong);
        if (vInt * vInt > xAsLong)
            vInt--;
        return BigInteger.valueOf(vInt);  }

    double xAsDub = x.doubleValue();
    BigInteger val;
    if (xAsDub < 2.1267e37) // 2.12e37 largest here since sqrt(long.max*long.max) > long.max
    {
        long vInt = (long)Math.sqrt(xAsDub);
        val = BigInteger.valueOf((vInt + x.divide(BigInteger.valueOf(vInt)).longValue()) >> 1);
    }
    else if (xAsDub < 4.3322e127) {
        // Convert a double to a BigInteger
        long bits = Double.doubleToLongBits(Math.sqrt(xAsDub));
        int exp = ((int) (bits >> 52) & 0x7ff) - 1075;
        val = BigInteger.valueOf((bits & ((1L << 52)) - 1) | (1L << 52)).shiftLeft(exp);

        val = x.divide(val).add(val).shiftRight(1);
        if (xAsDub > 2e63) {
            val = x.divide(val).add(val).shiftRight(1);  }
    }
    else // handle large numbers over 4.3322e127
    {
        int xLen = x.bitLength();
        int wantedPrecision = ((xLen + 1) / 2);
        int xLenMod = xLen + (xLen & 1) + 1;

        //////// Do the first Sqrt on Hardware ////////
        long tempX = x.shiftRight(xLenMod - 63).longValue();
        double tempSqrt1 = Math.sqrt(tempX);
        long valLong = Double.doubleToLongBits(tempSqrt1) & 0x1fffffffffffffL;

        if (valLong == 0)
            valLong = 1L << 53;

        //////// Classic Newton Iterations ////////
        val = BigInteger.valueOf(valLong).shiftLeft(53 - 1)
                .add((x.shiftRight(xLenMod - (3 * 53))).divide(BigInteger.valueOf(valLong)));

        int size = 106;
        for (; size < 256; size <<= 1) {
            val = val.shiftLeft(size - 1).add(x.shiftRight(xLenMod - (3 * size)).divide(val)); }

        if (xAsDub > 4e254) // 4e254 = 1<<845.77 
        {
            int numOfNewtonSteps = 31 - Integer.numberOfLeadingZeros(wantedPrecision / size) + 1;

            ////// Apply Starting Size ////////
            int wantedSize = (wantedPrecision >> numOfNewtonSteps) + 2;
            int needToShiftBy = size - wantedSize;
            val = val.shiftRight(needToShiftBy);

            size = wantedSize;
            do {
                //////// Newton Plus Iteration ////////
                int shiftX = xLenMod - (3 * size);
                BigInteger valSqrd = val.multiply(val).shiftLeft(size - 1);
                BigInteger valSU = x.shiftRight(shiftX).subtract(valSqrd);
                val = val.shiftLeft(size).add(valSU.divide(val));
                size *= 2;
            } while (size < wantedPrecision);
        }
        val = val.shiftRight(size - wantedPrecision);
    }

    // Detect a round ups. This function can be further optimized - see article.
    // For a ~7% speed bump the following line can be removed but round-ups will occur.
    if (val.multiply(val).compareTo(x) > 0)
        val = val.subtract(BigInteger.ONE);

    // // Enabling the below will guarantee an error is stopped for larger numbers.
    // // Note: As of this writing, there are no known errors.
    // BigInteger tmp = val.multiply(val);
    // if (tmp.compareTo(x) > 0)  {
    //     System.out.println("val^2(" + val.multiply(val).toString() + ") >=  x(" + x.toString() + ")"); 
    //     System.console().readLine();
    //     //throw new Exception("Sqrt function had internal error - value too high");   
    // }
    // if (tmp.add(val.shiftLeft(1)).add(BigInteger.ONE).compareTo(x) <= 0) {
    //     System.out.println("(val+1)^2(" + val.add(BigInteger.ONE).multiply(val.add(BigInteger.ONE)).toString() + ") >=  x(" + x.toString() + ")"); 
    //     System.console().readLine();
    //     //throw new Exception("Sqrt function had internal error - value too low");    
    // }

    return val;
}

這是與內置 BigInteger.Sqrt() 的性能比較

注意:每條橫線性能翻倍! 在此處輸入圖像描述

我只考慮平方根的整數部分,但你可以修改這個粗略的算法,以達到你想要的盡可能多的精度:

  public static void main(String args[]) {
    BigInteger N = new BigInteger(
            "17976931348623159077293051907890247336179769789423065727343008115"
                    + "77326758055056206869853794492129829595855013875371640157101398586"
                    + "47833778606925583497541085196591615128057575940752635007475935288"
                    + "71082364994994077189561705436114947486504671101510156394068052754"
                    + "0071584560878577663743040086340742855278549092581");
    System.out.println(N.toString(10).length());
    String sqrt = "";
    BigInteger divisor = BigInteger.ZERO;
    BigInteger toDivide = BigInteger.ZERO;
    String Nstr = N.toString(10);
    if (Nstr.length() % 2 == 1)
        Nstr = "0" + Nstr;
    for (int digitCount = 0; digitCount < Nstr.length(); digitCount += 2) {
        toDivide = toDivide.multiply(BigInteger.TEN).multiply(
                BigInteger.TEN);
        toDivide = toDivide.add(new BigInteger(Nstr.substring(digitCount,
                digitCount + 2)));
        String div = divisor.toString(10);
        divisor = divisor.add(new BigInteger(
                div.substring(div.length() - 1)));
        int into = tryMax(divisor, toDivide);
        divisor = divisor.multiply(BigInteger.TEN).add(
                BigInteger.valueOf(into));
        toDivide = toDivide.subtract(divisor.multiply(BigInteger
                .valueOf(into)));
        sqrt = sqrt + into;
    }
    System.out.println(String.format("Sqrt(%s) = %s", N, sqrt));
}

private static int tryMax(final BigInteger divisor,
        final BigInteger toDivide) {
    for (int i = 9; i > 0; i--) {
        BigInteger div = divisor.multiply(BigInteger.TEN).add(
                BigInteger.valueOf(i));
        if (div.multiply(BigInteger.valueOf(i)).compareTo(toDivide) <= 0)
            return i;
    }
    return 0;
}

您還可以使用二分搜索來找到 x 的平方根,您也可以將其乘以例如 10^10 並從 m^2 開始通過二分搜索找到像 m 這樣的整數

 System.out.println(m.divide(10^5)+"."+m.mod(10^5));

這是一個不使用 BigInteger.multiply 或 BigInteger.divide 的解決方案:

    private static final BigInteger ZERO  = BigInteger.ZERO;
    private static final BigInteger ONE   = BigInteger.ONE;
    private static final BigInteger TWO   = BigInteger.valueOf(2);
    private static final BigInteger THREE = BigInteger.valueOf(3);

    /**
     * This method computes sqrt(n) in O(n.bitLength()) time,
     * and computes it exactly. By "exactly", I mean it returns
     * not only the (floor of the) square root s, but also the
     * remainder r, such that r >= 0, n = s^2 + r, and
     * n < (s + 1)^2.
     *
     * @param n The argument n, as described above.
     *
     * @return An array of two values, where the first element
     *         of the array is s and the second is r, as
     *         described above.
     *
     * @throws IllegalArgumentException if n is not nonnegative.
     */
    public static BigInteger[] sqrt(BigInteger n) {
        if (n == null || n.signum() < 0) {
            throw new IllegalArgumentException();
        }

        int bl = n.bitLength();
        if ((bl & 1) != 0) {
            ++ bl;
        }

        BigInteger s = ZERO;
        BigInteger r = ZERO;

        while (bl >= 2) {
            s = s.shiftLeft(1);

            BigInteger crumb = n.testBit(-- bl)
                                ? (n.testBit(-- bl) ? THREE : TWO)
                                : (n.testBit(-- bl) ? ONE : ZERO);
            r = r.shiftLeft(2).add(crumb);

            BigInteger d = s.shiftLeft(1);
            if (d.compareTo(r) < 0) {
                s = s.add(ONE);
                r = r.subtract(d).subtract(ONE);
            }
        }

        assert r.signum() >= 0;
        assert n.equals(s.multiply(s).add(r));
        assert n.compareTo(s.add(ONE).multiply(s.add(ONE))) < 0;

        return new BigInteger[] {s, r};
    }

我上面發布的答案不適用於大數字(但有趣的是!)。 因此,發布用於確定平方根的二分搜索方法的正確性。

package com.example.so.squareroot;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>https://stackoverflow.com/questions/4407839/how-can-i-find-the-square-root-of-a-java-biginteger</p>
 * <p> Determine square-root of a number or its closest whole number (binary-search-approach) </p>
 * @author Ravindra
 * @since 07-July-2018
 * 
 */
public class BigIntegerSquareRootV2 {

    public static void main(String[] args) {

        List<BigInteger> listOfSquares = new ArrayList<BigInteger>();
        listOfSquares.add(BigInteger.valueOf(5).multiply(BigInteger.valueOf(5)).pow(2));
        listOfSquares.add(BigInteger.valueOf(11).multiply(BigInteger.valueOf(11)).pow(2));
        listOfSquares.add(BigInteger.valueOf(15485863).multiply(BigInteger.valueOf(10000019)).pow(2));
        listOfSquares.add(BigInteger.valueOf(533000401).multiply(BigInteger.valueOf(982451653)).pow(2));
        listOfSquares.add(BigInteger.valueOf(11).multiply(BigInteger.valueOf(23)));
        listOfSquares.add(BigInteger.valueOf(11).multiply(BigInteger.valueOf(23)).pow(2));


        for (BigInteger bigIntegerNumber : listOfSquares) {

            BigInteger squareRoot = calculateSquareRoot(bigIntegerNumber);

            System.out.println("Result :"+bigIntegerNumber+":"+squareRoot);
        }


        System.out.println("*********************************************************************");

        for (BigInteger bigIntegerNumber : listOfSquares) {

            BigInteger squareRoot = determineClosestWholeNumberSquareRoot(bigIntegerNumber);

            System.out.println("Result :"+bigIntegerNumber+":"+squareRoot);
        }

    }


    /*
Result :625:25
Result :14641:121
Result :23981286414105556927200571609:154858924231397
Result :274206311533451346298141971207799609:523647125012112853
Result :253:null
Result :64009:253
     */

    public static BigInteger calculateSquareRoot(BigInteger number) { 

        /*
         * Can be optimized by passing a bean to store the comparison result and avoid having to re-calculate.
         */
        BigInteger squareRootResult = determineClosestWholeNumberSquareRoot(number);
        if( squareRootResult.pow(2).equals(number)) {
            return squareRootResult;
        }

        return null;
    }


    /*
Result :625:25
Result :14641:121
Result :23981286414105556927200571609:154858924231397
Result :274206311533451346298141971207799609:523647125012112853
Result :253:15
Result :64009:253
     */
    private static BigInteger determineClosestWholeNumberSquareRoot(BigInteger number) {

        BigInteger result = null;

        if(number.equals(BigInteger.ONE)) {
            return BigInteger.ONE;
        } else if( number.equals(BigInteger.valueOf(2)) ) {
            return BigInteger.ONE;
        } else if( number.equals(BigInteger.valueOf(3)) ) {
            return BigInteger.ONE;
        } else if( number.equals(BigInteger.valueOf(4)) ) {
            return BigInteger.valueOf(2);
        }

        BigInteger tempBaseLow = BigInteger.valueOf(2);
        BigInteger tempBaseHigh = number.shiftRight(1); // divide by 2

        int loopCount = 11;

        while(true) {

            if( tempBaseHigh.subtract(tempBaseLow).compareTo(BigInteger.valueOf(loopCount)) == -1 ) { // for lower numbers use for-loop
                //System.out.println("Breaking out of while-loop.."); // uncomment-for-debugging
                break;
            }

            BigInteger tempBaseMid = tempBaseHigh.subtract(tempBaseLow).shiftRight(1).add(tempBaseLow); // effectively mid = [(high-low)/2]+low
            BigInteger tempBaseMidSquared = tempBaseMid.pow(2);
            int comparisonResultTemp = tempBaseMidSquared.compareTo(number);


            if(comparisonResultTemp == -1) { // move mid towards higher number
                tempBaseLow = tempBaseMid;
            } else if( comparisonResultTemp == 0 ) { // number is a square ! return the same !
                    return tempBaseMid;
            } else { // move mid towards lower number
                tempBaseHigh = tempBaseMid;
            }

        }

        BigInteger tempBasePrevious = tempBaseLow;
        BigInteger tempBaseCurrent = tempBaseLow;
        for(int i=0;i<(loopCount+1);i++) {
            BigInteger tempBaseSquared = tempBaseCurrent.pow(2);
            //System.out.println("Squared :"+tempBaseSquared); // uncomment-for-debugging
            int comparisonResultTempTwo = tempBaseSquared.compareTo(number);

            if( comparisonResultTempTwo == -1 ) { // move current to previous and increment current...
                tempBasePrevious = tempBaseCurrent;
                tempBaseCurrent = tempBaseCurrent.add(BigInteger.ONE);
            } else if( comparisonResultTempTwo == 0 ) { // is an exact match!
                tempBasePrevious = tempBaseCurrent;
                break;
            } else { // we've identified the point of deviation.. break..
                //System.out.println("breaking out of for-loop for square root..."); // uncomment-for-debugging
                break;
            }
        }

        result = tempBasePrevious;

        //System.out.println("Returning :"+result); // uncomment-for-debugging
        return result;

    }


}

問候拉文德拉

這是一種易於理解的方式,可能沒有最佳性能,但它可以在不到一秒的時間內為單個 BigInteger 提供解決方案。

public static BigInteger sqrt(BigInteger n) {
    BigInteger bottom = BigInteger.ONE;
    BigInteger top = n;
    BigInteger mid;
    while(true) {
        mid = top.add(bottom).divide(new BigInteger(""+2));
        top = mid;
        bottom = n.divide(top);
//            System.out.println("top:    "+top);
//            System.out.println("mid:    "+mid);
//            System.out.println("bottom: "+bottom);
        if(top.equals(bottom)) {
            return top;
        }
    }
}

C# 語言的語法與 Java 相似。 我寫了這個遞歸解決方案。

    static BigInteger fsqrt(BigInteger n)
    {
        string sn = n.ToString();
        return guess(n, BigInteger.Parse(sn.Substring(0, sn.Length >> 1)), 0);          
    }
    static BigInteger guess(BigInteger n, BigInteger g, BigInteger last)
    {
        if (last >= g - 1 && last <= g + 1) return g;
        else return guess(n, (g + (n / g)) >> 1, g);
    }

像這樣調用這段代碼(在 Java 中我猜它應該是“System.out.print”)。

Console.WriteLine(fsqrt(BigInteger.Parse("783648276815623658365871365876257862874628734627835648726")));

答案是:27993718524262253829858552106

免責聲明:我知道此方法不適用於小於 10 的數字; 這是一個 BigInteger 平方根方法。

這很容易補救。 將第一種方法更改為以下方法,以便為遞歸部分留出一些喘息的空間。

    static BigInteger fsqrt(BigInteger n)
    {
        if (n > 999)
        {
           string sn = n.ToString();
           return guess(n, BigInteger.Parse(sn.Substring(0, sn.Length >> 1)), 0);
        }
        else return guess(n, n >> 1, 0);            
    }

一條線就可以完成我認為的工作。

Math.pow(bigInt.doubleValue(), (1/n));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM