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

后端 未结 19 1121
[愿得一人]
[愿得一人] 2020-11-28 08:10

Is there a library that will find the square root of a BigInteger? I want it computed offline - only once, and not inside any loop. So even computationally expensive solutio

19条回答
  •  清酒与你
    2020-11-28 08:37

    Here's a solution that does not use BigInteger.multiply or 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};
        }
    

提交回复
热议问题