Проверьте, не является ли BigInteger идеальным квадратом
У меня есть значение BigInteger, скажем, 282 и находится внутри переменной x. Теперь я хочу написать цикл while, который гласит:
while b2 isn't a perfect square:
a ← a + 1
b2 ← a*a - N
endwhile
Как бы я сделал такую вещь, используя BigInteger?
EDIT: цель для этого, чтобы я мог написать этот метод. Как говорится в статье, необходимо проверить, не является ли b2 квадратным.
4 ответов
вычислите целочисленный квадратный корень, затем проверьте, что его квадрат - это ваше число. Вот мой метод вычисления квадратного корня с помощью метод цапли:
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;
}
Я нашел используемый метод sqrt здесь, и упрощенный квадратный тест.
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;
}
Я использую этот:
SQRPerfect я хочу проверить: Это также имеет хороший квадратный корень, поэтому вы можете использовать его, если вам это нужно отдельно. Вы можете немного ускорить, если вы принесете квадратный корень внутри идеальный квадрат, но мне нравится иметь обе функции.
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);
}
Не используйте это...
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
}
Как прокомментировал Кристиан Семрау ниже-это не работает. Извините за неправильный ответ.