views:

375

answers:

3

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.

+4  A: 

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
Note that isSqrt is an internal helper function, not the function you are after.
starblue
+2  A: 

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
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
A: 

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.

koppernickus
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
@Christian +1, good catch, my solution is very bad
koppernickus