此问题是对此处帖子的跟进:Fastest way to determine if an integer's square root is an integer,What's a good algorithm to determine if an input is a perfect square?。
其中一个帖子有这个解决方案,可以查找给定的数字是否为perfect square
:
public final static boolean isPerfectSquare(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;
}
}
这是一个简洁的解决方案,完美无缺。但是没有详细解释它是如何工作的,或者更重要的是如何得出这个解决方案。 我想知道如何推导出这个解决方案。
答案 0 :(得分:3)
虽然这个问题不是直接编程,但它仍然与选择的解决方法有关。这就是为什么我会发布正确的解释。显然,x & 0xF
只相当于x % 16
- 即从除法到16的模数(因为它将留下相应的位。但是,这个技巧只适用于2的幂)。
这个方法基于完美广场非常重要的事情:
如果整数K
被分为任何整数b
且模r
(K%b = r
},那么K 2 < / sup>和r 2 除以b
将得到相同的模数。
为什么呢?实际上,我们有:K 2 -r 2 =(Kr)(K + r)和K-r
将被归为b
整数结果(因为r
是K
的模数除以b
)
这就是b=16
:
r r^2 (r^2)%16 0 ----> 0 ---> 0 1 ----> 1 ---> 1 2 ----> 4 ---> 4 3 ----> 9 ---> 9 4 ---> 16 ---> 0 5 ---> 25 ---> 9 6 ---> 36 ---> 4 7 ---> 49 ---> 1 8 ---> 64 ---> 0 9 ---> 81 ---> 1 10 --> 100 ---> 4 11 --> 121 ---> 9 12 --> 144 ---> 0 13 --> 169 ---> 9 14 --> 196 ---> 4 15 --> 225 ---> 1
所以,正如你所看到的,如果r
来自完美正方形的除法,则模必须与r^2%16
的模数相同 - 因此,它可以是仅 0
,1
,4
和9
更重要的一点是:这是必要的条件,对于完美的正方形而不是足够的条件(所以点是“如果modulo不是0,1,4或9,那么数字不是完美的方形“,但它仍然不等于”如果模数为IS 0,1,4或9则数字IS完美正方形“简单样本为{{ 1}}:17
但是17不是完美的正方形)这就是为什么即使满足模数条件,方法仍然使用
返回tst * tst == n;
-i.e。通过计算它的平方根来测试17%16 = 1
是完美的平方。所以这种方法大约会快4倍 - 因为从16个可能的模数n
到12,我们总能返回r
。
答案 1 :(得分:2)
n & 0xF
只选择n的最后4位,因为0xF
是二进制的1111
。实际上,它相当于当n除以16时得到余数。
此算法利用以下事实:对于完美的正方形m
,m % 16
只能是0
,1
,4
或{{}}之一{1}}。可以证明如下:
任何自然数9
都可以表示为n
,4k
,4k+1
或4k+2
(对于某些自然数4k+3
)。
然后,k
可以是n^2
,(4k)^2
,(4k+1)^2
或(4k+2)^2
。
=&GT; (4k+3)^2
可以是n^2
,16k^2
,16k^2+8k+1
或16k^2+16k+4
。
如果16k^2+24k+9
为n^2
,则16k^2
显然为0.
如果n^2 % 16
为n^2
,16k^2+8k+1
,则取决于n^2 % 16 = (8k+1) % 16 = (8k % 16) + 1 = 0 or 9
是偶数还是奇数。
如果k
为n^2
,16k^2+16k+4
。
如果n^2 % 16 = 4
为n^2
,16k^2+24k+9
取决于k是奇数还是偶数。
因此,n^2 % 16 = (24k+9) % 16 = (16k+8k+9) % 16 = 1 or 9
只能是n^2 % 16
。