Determine if an Integer’s Square Root Is an Integer in Java – 在Java中判断一个整数的平方根是否为整数

最后修改: 2021年 1月 14日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

A perfect square is a number that can be expressed as the product of two equal integers.

完全平方数是一个可以表示为两个相等的整数之积的数字。

In this article, we’ll discover multiple ways to determine if an integer is a perfect square in Java. Also, we’ll discuss the advantages and disadvantages of each technique to determine its efficiency and which is the fastest.

在这篇文章中,我们将发现多种方法来确定一个整数是否是Java中的完全平方。同时,我们将讨论每种技术的优缺点,以确定其效率,以及哪种技术是最快的。

2. Checking if an Integer Is a Perfect Square

2.检查一个整数是否为完全平方

As we know, Java gives us two data types for defining an integer. The first one is int, which represents the number in 32 bits, and the other is long, which represents the number in 64 bits. In this article, we’ll use the long data type to handle the worst case (the largest possible integer).

正如我们所知,Java为我们提供了两种定义整数的数据类型。第一种是int,用32位表示数字,另一种是long,用64位表示数字。在这篇文章中,我们将使用long数据类型来处理最坏的情况(最大的可能整数)。

Since Java represents the long number in 64 bits, the range of the long number is from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. And, since we’re handling perfect squares, we’re only concerned with handling the set of positive integers because multiplying any integer by itself will always produce a positive number.

由于Java用64位表示长数,所以长数的范围是从-9,223,372,036,854,775,808到9,223,372,036,854,775,807。而且,由于我们正在处理完全平方,我们只关心处理正整数的集合,因为任何整数与自身相乘总是会产生一个正数。

In addition, since the largest number is about  263, that means there are about 231.5 integers whose square is less than 263. Also, we can suppose that having a lookup table of those numbers is inefficient.

此外,由于最大的数字约为263,这意味着有大约231.5个整数的平方小于263。另外,我们可以假设有一个这些数字的查询表是低效的。

2.1. Using the sqrt Method in Java

2.1.在Java中使用sqrt方法

The easiest and most straightforward way to check whether an integer is a perfect square is to use the sqrt function. As we know, the sqrt function returns a double value. So, what we need to do is to cast the result to int and multiply it by itself. Then, we check if the result is equal to the integer we started with:

检查一个整数是否是完全平方的最简单和最直接的方法是使用sqrt函数。正如我们所知,sqrt函数返回一个double值。因此,我们需要做的是将结果转换为int,并将其乘以自身。然后,我们检查结果是否等于我们开始使用的整数。

public static boolean isPerfectSquareByUsingSqrt(long n) {
    if (n <= 0) {
        return false;
    }
    double squareRoot = Math.sqrt(n);
    long tst = (long)(squareRoot + 0.5);
    return tst*tst == n;
}

Note that we may need to add 0.5 to the result due to the precision errors we can encounter when dealing with double values. Sometimes, integers could be represented with a decimal point when assigned to a double variable.

请注意,由于我们在处理double值时可能会遇到精度误差,所以我们可能需要在结果中加上0.5。有时,整数在分配给double变量时可以用小数点表示。

For example, if we assign the number 3 to a double variable, then the value of it maybe 3.00000001 or 2.99999999. So, to avoid this representation, we add 0.5 before casting it to a long to make sure that we’re getting the actual value.

例如,如果我们将数字3分配给一个double变量,那么它的值可能是3.00000001或2.99999999。所以,为了避免这种表现形式,我们在将其转换为long之前加上0.5,以确保我们得到的是实际值。

In addition, if we test the sqrt function with one number, we’ll notice that the execution time is fast. On the other hand, if we need to call the sqrt function many times, and we try to reduce the number of operations executed by the sqrt function, this kind of micro-optimization could actually make a difference.

此外,如果我们用一个数字测试sqrt函数,我们会发现执行时间很快。另一方面,如果我们需要多次调用sqrt函数,并且我们试图减少sqrt函数执行的操作数量,这种微观优化实际上可能会带来变化。

2.2. Using Binary Search

2.2.使用二进制搜索

We can use a binary search to find the square root of a number without using the sqrt function.

我们可以使用二进制搜索来寻找一个数字的平方根,而不使用sqrt函数

Since the range of the number is from 1 to 263, the root is between 1 and 231.5. So, the binary search algorithm needs about 16 iterations to get the square root:

由于这个数字的范围是1到263,所以根在1到231.5之间。因此,二进制搜索算法需要大约16次迭代才能得到平方根。

public boolean isPerfectSquareByUsingBinarySearch(long low, long high, long number) {
    long check = (low + high) / 2L;
    if (high < low) {
        return false;
    }
    if (number == check * check) {
        return true;
    }
    else if (number < check * check) {
        high = check - 1L;
        return isPerfectSquareByUsingBinarySearch(low, high, number);
    }
    else {
        low = check + 1L;
        return isPerfectSquareByUsingBinarySearch(low, high, number);
    }
}

2.3. Enhancements on Binary Search

2.3.对二进制搜索的改进

To enhance the binary search, we can notice that if we determine the number of digits of the basic number, that gives us the range of the root.

为了加强二进制搜索,我们可以注意到,如果我们确定基本数字的位数,就可以得到根的范围。

For example, if the number consists of one digit only, then the range of the square root is between 1 and 4. The reason is that the maximum integer from one digit is 9 and its root is 3. In addition, if the number is composed of two digits, the range is between 4 and 10, and so on.

例如,如果数字只由一位数组成,那么平方根的范围就在1和4之间。原因是一位数的最大整数是9,其根是3。此外,如果数字由两位数组成,其范围在4和10之间,以此类推。

So, we can build a lookup table to specify the range of the square root based on the number of digits of the number we start with. That will reduce the range of the binary search. So, it’ll need fewer iterations to get the square root:

因此,我们可以建立一个查找表,根据我们开始的数字的位数来指定平方根的范围。这将减少二进制搜索的范围。因此,它需要更少的迭代来获得平方根。

public class BinarySearchRange {
    private long low;
    private long high;

    // standard constructor and getters
}
private void initiateOptimizedBinarySearchLookupTable() {
    lookupTable.add(new BinarySearchRange());
    lookupTable.add(new BinarySearchRange(1L, 4L));
    lookupTable.add(new BinarySearchRange(3L, 10L));
    for (int i = 3; i < 20; i++) {
        lookupTable.add(
          new BinarySearchRange(
            lookupTable.get(i - 2).low * 10,
            lookupTable.get(i - 2).high * 10));
    }
}
public boolean isPerfectSquareByUsingOptimizedBinarySearch(long number) {
    int numberOfDigits = Long.toString(number).length();
    return isPerfectSquareByUsingBinarySearch(
      lookupTable.get(numberOfDigits).low,
      lookupTable.get(numberOfDigits).high,
     number);
}

2.4. Newton’s Method With Integer Arithmetic

2.4.带有整数算术的牛顿方法

In general, we can use Newton’s method to get the square root of any number, even non-integers. The basic idea of Newton’s method is to suppose a number X is the square root of a number N. After that, we can start a loop and keep calculating the root, which will surely move towards the correct square root of N.

一般来说,我们可以用牛顿方法来得到任何数字的平方根,甚至是非整数。牛顿方法的基本思想是假设一个数字X是一个数字N的平方根。之后,我们可以启动一个循环,不断计算根,这肯定会朝着N的正确平方根前进。

However, with some modifications to Newton’s method, we can use it to check whether an integer is a perfect square:

然而,经过对牛顿方法的一些修改,我们可以用它来检查一个整数是否是完全平方:

public static boolean isPerfectSquareByUsingNewtonMethod(long n) {
    long x1 = n;
    long x2 = 1L;
    while (x1 > x2) {
        x1 = (x1 + x2) / 2L;
        x2 = n / x1;
    }
    return x1 == x2 && n % x1 == 0L;
}

3. Optimizing Integer Square Root Algorithms

3.优化整数平方根算法

As we discussed, there are multiple algorithms to check the square roots of an integer. Nevertheless, we can always optimize any algorithm by using some tricks.

正如我们所讨论的,有多种算法可以检查整数的平方根。尽管如此,我们总是可以通过使用一些技巧来优化任何算法。

Tricks should consider avoiding executing the main operations that will determine the square root. For example, we can exclude negative numbers directly.

技巧应该考虑避免执行将决定平方根的主要操作。例如,我们可以直接排除负数。

One of the facts that we can use is “perfect squares can only end in 0, 1, 4, or 9 in base 16”. So, we can convert an integer to base 16 before starting the computations. After that, we exclude the cases that consider the number as a non-perfect square root:

我们可以利用的一个事实是“完全平方在基数16中只能以0、1、4或9结尾”。因此,我们可以在开始计算之前将一个整数转换成基数16。之后,我们排除那些认为该数字为非完美平方根的情况。

public static boolean isPerfectSquareWithOptimization(long n) {
    if (n < 0) {
        return false;
    }
    switch((int)(n & 0xF)) {
        case 0: case 1: case 4: case 9:
            long tst = (long)Math.sqrt(n);
            return tst*tst == n;
        default:
            return false;
    }
}

4. Conclusion

4.总结

In this article, we discussed multiple ways to determine whether an integer is a perfect square or not. As we’ve seen, we can always enhance the algorithms by using some tricks.

在这篇文章中,我们讨论了确定一个整数是否是完全平方的多种方法。正如我们所看到的,我们总是可以通过使用一些小技巧来增强算法。

These tricks will exclude a large number of cases before starting the main operation of the algorithm. The reason is that a lot of integers can be determined as non-perfect squares easily.

在开始算法的主要操作之前,这些技巧将排除大量的情况。原因是很多整数可以很容易地被确定为非完美的平方。

As always, the code presented in this article is available over on GitHub.

一如既往,本文介绍的代码可在GitHub上获得over