8

I have a BigInteger value, let's say it is 282 and is inside the variable x. I now want to write a while loop that states:

while b2 isn't a perfect square:
    a ← a + 1
    b2 ← a*a - N
endwhile

How would I do such a thing using BigInteger?

EDIT: The purpose for this is so I can write this method. As the article states one must check if b2 is not square.

Mike B
  • 12,768
  • 20
  • 83
  • 109

7 Answers7

12

Compute the integer square root, then check that its square is your number. Here is my method of computing the square root using Heron's method:

private static final BigInteger TWO = BigInteger.valueOf(2);


/**
 * Computes the integer square root of a number.
 *
 * @param n  The number.
 *
 * @return  The integer square root, i.e. the largest number whose square
 *     doesn't exceed n.
 */
public static BigInteger sqrt(BigInteger n)
{
    if (n.signum() >= 0)
    {
        final int bitLength = n.bitLength();
        BigInteger root = BigInteger.ONE.shiftLeft(bitLength / 2);

        while (!isSqrt(n, root))
        {
            root = root.add(n.divide(root)).divide(TWO);
        }
        return root;
    }
    else
    {
        throw new ArithmeticException("square root of negative number");
    }
}


private static boolean isSqrt(BigInteger n, BigInteger root)
{
    final BigInteger lowerBound = root.pow(2);
    final BigInteger upperBound = root.add(BigInteger.ONE).pow(2);
    return lowerBound.compareTo(n) <= 0
        && n.compareTo(upperBound) < 0;
}
starblue
  • 55,348
  • 14
  • 97
  • 151
  • Note that isSqrt is an internal helper function, not the function you are after. – starblue Apr 21 '10 at 20:40
  • The code in this answer is using class methods that do NOT exist in the BigInteger class of Visual Studio 2019 such as .signum(), .ONE.shiftLeft() etc. @starblue are you using extension methods that missing from the answer? – Cornelius J. van Dyk Feb 15 '21 at 21:07
  • @CorneliusJ.vanDyk No, this is Java. (I have no idea what you think this is.) – starblue Mar 08 '21 at 15:33
  • Forgive me for not realizing that this thread is about Java since nowhere in does it say Java in the thread. I thought we were talking C# since C# also contains the BigInteger class. – Cornelius J. van Dyk Mar 11 '21 at 19:59
2

I found a sqrt method used here, and simplified the square test.

private static final BigInteger b100 = new BigInteger("100");
private static final boolean[] isSquareResidue;
static{
    isSquareResidue = new boolean[100];
    for(int i =0;i<100;i++){
        isSquareResidue[(i*i)%100]=true;
    }
}

public static boolean isSquare(final BigInteger r) {
    final int y = (int) r.mod(b100).longValue();
    boolean check = false;
    if (isSquareResidue[y]) {
        final BigInteger temp = sqrt(r);
        if (r.compareTo(temp.pow(2)) == 0) {
            check = true;
        }
    }
    return check;
}

public static BigInteger sqrt(final BigInteger val) {
    final BigInteger two = BigInteger.valueOf(2);
    BigInteger a = BigInteger.ONE.shiftLeft(val.bitLength() / 2);
    BigInteger b;
    do {
        b = val.divide(a);
        a = (a.add(b)).divide(two);
    } while (a.subtract(b).abs().compareTo(two) >= 0);
    return a;
}
Christian Semrau
  • 8,913
  • 2
  • 32
  • 39
  • 1
    The isSquareResidue array contains all square residues mod 100. Checking residues allows us to compute the sqrt only for square residues, which are only 22 of 100. – Christian Semrau Apr 21 '10 at 18:56
1
public static Boolean PerfectSQR(BigInteger A){BigInteger B=A.sqrt(), C=B.multiply(B);return (C.equals(A));}
dbc
  • 104,963
  • 20
  • 228
  • 340
0

DON'T use this...

 BigInteger n = ...;
 double n_as_double = n.doubleValue();
 double n_sqrt = Math.sqrt(n_as_double);
 BigInteger n_sqrt_as_int = new BigDecimal(n_sqrt).toBigInteger();
 if (n_sqrt_as_int.pow(2).equals(n)) {
  // number is perfect square
 }

As Christian Semrau commented below - this doesn't work. I am sorry for posting incorrect answer.

kopper
  • 2,676
  • 1
  • 16
  • 17
  • 2
    This will fail for large values of n, because n and n+1 will have the same double value, so if n is a square, the test cannot return true for n and return false for n+1. A value of n, for which the test returns false in error, is the square of 12345678901234567. – Christian Semrau Apr 21 '10 at 19:04
0
using System.Numerics; // needed for BigInteger

/* Variables */
BigInteger a, b, b2, n, p, q;
int flag;

/* Assign Data */
n = 10147;
a = iSqrt(n);

/* Algorithm */
do
{   a = a + 1;
    b2 = (a * a) – n;
    b = iSqrt(b2);
    flag = BigInteger.Compare(b * b, b2);
} while(flag != 0);

/* Output Data */
p = a + b;
q = a – b;


/* Method */
    private static BigInteger iSqrt(BigInteger num)
    { // Finds the integer square root of a positive number            
        if (0 == num) { return 0; }     // Avoid zero divide            
        BigInteger n = (num / 2) + 1;   // Initial estimate, never low            
        BigInteger n1 = (n + (num / n)) / 2;
        while (n1 < n)
        {   n = n1;
            n1 = (n + (num / n)) / 2;
        }
        return n;
    } // end iSqrt()
Optionparty
  • 101
  • 2
0
private static boolean isSqrt(BigInteger n, BigInteger root)
{
    final BigInteger lowerBound = root.pow(2);
    final BigInteger upperBound = root.add(BigInteger.ONE).pow(2);
    return lowerBound.compareTo(n) <= 0
        && n.compareTo(upperBound) < 0;
}

I tried the above using JavaScript BigInt:

function isPerfectSqrt(n, root) {
  const lowerBound = root**2n;
  const upperBound = (root+1n)**2n
  return lowerBound <= n && n < upperBound;
}

And found it was only about 60% as fast (in Node V8) as the one-liner:

function isPerfectSqrt(n, root) {
  return (n/root === root && n%root === 0n)
}
Jeff Lowery
  • 2,492
  • 2
  • 32
  • 40
0

The number you want to do a perfect square test on is A. B is the integer square root of A and the .sqrt() function returns the integer lower floor of the square root. The Boolean of B*B=A is returned. The Boolean return is "true" if it is a perfect square and "false" if it is not a perfect square.

public static Boolean PerfectSQR(BigInteger A) {
    BigInteger B = A.sqrt();
    return B.multiply(B).equals(A);
}

An alternative is to use the sqrtAndRemainder() function. If the remainder, B[1], is zero it is a perfect square. The boolean TRUE then is returned as shown below.

public static Boolean PerfectSQR(BigInteger A) {
    BigInteger [] B=A.sqrtAndRemainder();
    return B[1].equals(BigInteger.ZERO);
}