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.
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;
}
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;
}
I use this:
SQRPerfect is the number I want to test:
This also has a nice Square Root so you get to use this as well if you need it seperately. You can get a little speed up if you bring the Square Root inside the Perfect Square test, but I like having both functions.
if(PerfectSQR(SQRPerfect)){
Do Something
}
public static Boolean PerfectSQR(BigInteger A) {
Boolean p=false;
BigInteger B=SQRT(A);
BigInteger C=B.multiply(B);
if (C.equals(A)){p=true;}
return p;
}
public static BigInteger SQRT(BigInteger A) {
BigInteger a=BigInteger.ONE,b=A.shiftRight(5).add(BigInteger.valueOf(8));
while ((b.compareTo(a))>=0){
BigInteger mid = a.add(b).shiftRight(1);
if (mid.multiply(mid).compareTo(A)>0){b=mid.subtract(BigInteger.ONE);}
else{a=mid.add(BigInteger.ONE);}
}
return a.subtract(BigInteger.ONE);
}
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.