检查一个数字是否是一个完美的正方形

时间:2010-03-22 00:48:51

标签: python math

我如何检查一个数字是否是一个完美的正方形?

速度无关紧要,现在,只是工作。

24 个答案:

答案 0 :(得分:105)

依赖任何浮点计算(math.sqrt(x)x**0.5)的问题是你无法确定它是否准确(对于足够大的整数x,它赢了不会,甚至可能溢出。幸运的是(如果一个人不着急;-)有许多纯整数方法,例如以下......:

def is_square(apositiveint):
  x = apositiveint // 2
  seen = set([x])
  while x * x != apositiveint:
    x = (x + (apositiveint // x)) // 2
    if x in seen: return False
    seen.add(x)
  return True

for i in range(110, 130):
   print i, is_square(i)

提示:它基于平方根的“巴比伦算法”,请参阅wikipedia。它 适用于任何正数,你有足够的内存让计算继续完成; - )。

编辑:让我们看一个例子......

x = 12345678987654321234567 ** 2

for i in range(x, x+2):
   print i, is_square(i)

根据需要打印(并且在合理的时间内打印; - ):

152415789666209426002111556165263283035677489 True
152415789666209426002111556165263283035677490 False

在你提出基于浮点中间结果的解决方案之前,请确保它们在这个简单的例子中正常工作 - 它不是 很难(如果是sqrt,你只需要一些额外的检查)计算有点不对,只需要稍加注意。

然后尝试使用x**7并找到解决问题的聪明方法,

OverflowError: long int too large to convert to float

当然,随着数字的不断增长,你必须变得越来越聪明。

如果我 匆忙,当然,我会使用gmpy - 但是,我显然有偏见; - )。

>>> import gmpy
>>> gmpy.is_square(x**7)
1
>>> gmpy.is_square(x**7 + 1)
0

是的,我知道,这就像是作弊一样容易(我对Python的感觉有点像一般;-) - 根本没有聪明,只是完美的直接性和简单性(并且,在gmpy的情况下) ,纯粹的速度; - )......

答案 1 :(得分:27)

使用牛顿方法快速归零最近的整数平方根,然后将其平方并查看它是否是您的数字。请参阅isqrt

答案 2 :(得分:16)

因为在处理浮点计算时(例如计算平方根的这些方法),你永远不能依赖于精确的比较,所以

更容易出错。
import math
def is_square(integer):
    root = math.sqrt(integer)
    if int(root + 0.5) ** 2 == integer: 
        return True
    else:
        return False

想象一下integer9math.sqrt(9)可以是3.0,但它也可以是2.999993.00001,因此将结果平方关闭并不可靠。知道int占用最低价值,首先将浮动值增加0.5意味着如果我们处于float仍有的范围内,我们将获得我们正在寻找的价值足够精细的分辨率来表示我们正在寻找的数字附近的数字。

答案 3 :(得分:12)

import math
if (math.sqrt(number)-int(math.sqrt(number))):
    print "it's not a perfect square"

完美正方形是一个数字,可以表示为两个相等整数的乘积。 math.sqrt(number)返回floatint(math.sqrt(number))将结果投放到int

如果平方根是一个整数,例如3,那么math.sqrt(number) - int(math.sqrt(number))将为0,if语句将为False。如果平方根是像3.2这样的实数,那么它将是True并且打印"它不是一个完美的正方形"。

答案 4 :(得分:8)

如果您有兴趣,我会在math stackexchange, "Detecting perfect squares faster than by extracting square root"对类似问题做出纯数学回答。

我自己实现的isSquare(n)可能不是最好的,但我喜欢它。花了几个月的时间学习数学理论,数字计算和python编程,将自己与其他贡献者等进行比较,真正点击这个方法。我喜欢它的简单性和高效性。我没有看到更好。告诉我你的想法。

def isSquare(n):
    ## Trivial checks
    if type(n) != int:  ## integer
        return False
    if n < 0:      ## positivity
        return False
    if n == 0:      ## 0 pass
        return True

    ## Reduction by powers of 4 with bit-logic
    while n&3 == 0:    
        n=n>>2

    ## Simple bit-logic test. All perfect squares, in binary,
    ## end in 001, when powers of 4 are factored out.
    if n&7 != 1:
        return False

    if n==1:
        return True  ## is power of 4, or even power of 2


    ## Simple modulo equivalency test
    c = n%10
    if c in {3, 7}:
        return False  ## Not 1,4,5,6,9 in mod 10
    if n % 7 in {3, 5, 6}:
        return False  ## Not 1,2,4 mod 7
    if n % 9 in {2,3,5,6,8}:
        return False  
    if n % 13 in {2,5,6,7,8,11}:
        return False  

    ## Other patterns
    if c == 5:  ## if it ends in a 5
        if (n//10)%10 != 2:
            return False    ## then it must end in 25
        if (n//100)%10 not in {0,2,6}: 
            return False    ## and in 025, 225, or 625
        if (n//100)%10 == 6:
            if (n//1000)%10 not in {0,5}:
                return False    ## that is, 0625 or 5625
    else:
        if (n//10)%4 != 0:
            return False    ## (4k)*10 + (1,9)


    ## Babylonian Algorithm. Finding the integer square root.
    ## Root extraction.
    s = (len(str(n))-1) // 2
    x = (10**s) * 4

    A = {x, n}
    while x * x != n:
        x = (x + (n // x)) >> 1
        if x in A:
            return False
        A.add(x)
    return True

非常直接。首先,它检查我们是否有一个整数,然后是一个正整数。否则就没有意义了。它允许0作为True传递(必要或者下一个块是无限循环)。

下一代码块使用位移和位逻辑运算在非常快速的子算法中系统地消除4的幂。如果可能的话,我们最终没有找到原始n的isSquare,而是找到了按4的幂缩小的k

第三个代码块执行简单的布尔位逻辑测试。任意完美正方形的二进制最不重要的三位数字是001.总是。无论如何,除了4的幂之外,还要保留已经计入的前导零。如果测试失败,你会立刻知道它不是正方形。如果它通过,你无法确定。

此外,如果我们以测试值的最终结果为1,那么测试编号最初是4的幂,包括1本身。

与第三个块一样,第四个块使用简单模数运算符测试十进制的一个位置值,并且倾向于捕获滑过前一个测试的值。还有mod 7,mod 8,mod 9和mod 13测试。

第五个代码块检查一些众所周知的完美方形图案。以1或9结尾的数字前面加上四的倍数。以5结尾的数字必须以5625,0625,225或025结尾。我已经包含了其他人,但意识到它们是多余的或从未实际使用过。

最后,第六段代码非常类似于顶级回答者 - 亚历克斯马尔泰利 - 回答的问题。基本上使用古老的巴比伦算法找到平方根,但是在忽略浮点的同时将其限制为整数值。完成速度和扩展可测试值的大小。我使用集合而不是列表,因为它花费的时间少得多,我使用了位移而不是除以2,我巧妙地选择了初始起始值。

顺便说一下,我确实测试了Alex Martelli推荐的测试编号,以及几个数量级更大的数字,例如:

x=1000199838770766116385386300483414671297203029840113913153824086810909168246772838680374612768821282446322068401699727842499994541063844393713189701844134801239504543830737724442006577672181059194558045164589783791764790043104263404683317158624270845302200548606715007310112016456397357027095564872551184907513312382763025454118825703090010401842892088063527451562032322039937924274426211671442740679624285180817682659081248396873230975882215128049713559849427311798959652681930663843994067353808298002406164092996533923220683447265882968239141724624870704231013642255563984374257471112743917655991279898690480703935007493906644744151022265929975993911186879561257100479593516979735117799410600147341193819147290056586421994333004992422258618475766549646258761885662783430625 ** 2
for i in range(x, x+2):
    print(i, isSquare(i))

打印出以下结果:

1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890625 True
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890626 False

它在0.33秒内就完成了。

在我看来,我的算法与Alex Martelli的算法一样,具有其所有优点,但具有高效的简单测试拒绝的额外好处,可节省大量时间,更不用说减少测试数量的大小通过4的幂,可以提高速度,效率,准确性和可测试数字的大小。在非Python实现中可能尤其如此。

在巴比伦根提取甚至实施之前,大约99%的整数被拒绝为非正方形,并且在2/3时巴比伦人拒绝整数。尽管这些测试并没有显着加快这一过程,但通过将4 的所有权力划分为,将所有测试数量减少到一个奇数加速了巴比伦测试。

我做了时间比较测试。我连续测试了1到10百万的所有整数。仅使用巴比伦方法(使用我特别定制的初始猜测),我的Surface 3平均需要165秒(准确度为100%)。仅使用我的算法中的逻辑测试(不包括巴比伦),它花费了127秒,它拒绝了所有整数的99%作为非正方形而没有错误地拒绝任何完美的正方形。在那些通过的整数中,只有3%是完美的正方形(密度高得多)。使用上面使用逻辑测试和巴比伦根提取的完整算法,我们具有100%的准确性,并且仅在14秒内完成测试。前100万个整数大约需要2分45秒才能完成测试。

编辑:我已经能够进一步缩短时间。我现在可以在1分40秒内测试0到1亿的整数。浪费了大量时间来检查数据类型和积极性。消除前两个检查,我将实验缩短了一分钟。必须假设用户足够聪明,知道负片和浮点数不是完美的正方形。

答案 5 :(得分:6)

我是Stack Overflow的新手,并快速浏览以找到解决方案。我刚刚在另一个线程(Finding perfect squares)上发布了上面一些示例的略微变化,并认为我在这里包含了一些细微的变化(使用nsqrt作为临时变量),如果它是兴趣/用途:

import math

def is_perfect_square(n):
  if not ( isinstance(n, (int, long)) and ( n >= 0 ) ):
    return False 
  else:
    nsqrt = math.sqrt(n)
    return nsqrt == math.trunc(nsqrt)

答案 6 :(得分:4)

我的回答是:

def checkSquare(x):return x**.5%1==0

这基本上是一个平方根,然后以1为模来去除整数部分,如果结果是0则返回True否则返回False。在这种情况下,x可以是任何大数,只是没有python可以处理的最大浮点数那么大:1.7976931348623157e + 308

答案 7 :(得分:4)

这可以使用This article来解决,以获得任意精确的平方根并轻松检查&#34;准确性&#34;:

# I just kept mashing the numpad for awhile :-)
>>> base = 100009991439393999999393939398348438492389402490289028439083249803434098349083490340934903498034098390834980349083490384903843908309390282930823940230932490340983098349032098324908324098339779438974879480379380439748093874970843479280329708324970832497804329783429874329873429870234987234978034297804329782349783249873249870234987034298703249780349783497832497823497823497803429780324
>>> sqr = base ** 2
>>> sqr ** 0.5  # Too large to use floating point math
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: int too large to convert to float

>>> is_perfect_power(sqr)
True
>>> is_perfect_power(sqr-1)
False
>>> is_perfect_power(sqr+1)
False

对于具有真正巨大价值的演示:

gmpy2.mpz(x).is_square()

如果你增加被测试值的大小,这最终变得相当慢(200,000位方块接近一秒),但对于更温和的数字(比如20,000位),它仍然是比人类注意到的单个值更快(在我的机器上约33毫秒)。但由于速度并不是您最关心的问题,因此使用Python的标准库是一种很好的方法。

当然,使用the decimal module并测试@RequestMapping(value = "/users/{userId}/update/password", method = RequestMethod.PUT) 速度要快得多,但如果第三方套餐不是你的东西,那么上面的效果会非常好。

答案 8 :(得分:3)

这是我的方法

int(n**0.5)**2 == int(n)

取数字的平方根转换为整数然后取平方  如果数字相等那么它就是一个完美的正方形,否则就没有了。

答案 9 :(得分:2)

您可以二进制搜索圆角平方根。将结果平方以查看它是否与原始值匹配。

你可能会对FogleBirds的答案感觉更好 - 尽管要小心,因为浮点运算是近似的,这可能会让这种方法失效。原则上你可以从一个大整数中获得误报,例如,由于精度损失,这个整数大于一个完整的正方形。

答案 10 :(得分:1)

如果除以平方根后剩下的模数(余数)为0,则它​​是一个理想平方。

def is_square(num: int) -> bool:
    return num % math.sqrt(num) == 0

我对照最多1000个完美正方形的列表进行了检查。

答案 11 :(得分:1)

这在数字上就像你可能拥有的天真解决方案一样。它适用于少数人。

def is_perfect_square(n):
    return (n ** .5).is_integer()

显然它失败了很多,例如152415789666209426002111556165263283035677490。

答案 12 :(得分:1)

我认为这很有效,而且非常简单:

from math import sqrt

def is_perfect_square(num):
    return int(sqrt(num)) == sqrt(num)

答案 13 :(得分:1)

如果你想循环一个范围并为每个不是完美正方形的数字做一些事情,你可以这样做:

def non_squares(upper):
    next_square = 0
    diff = 1
    for i in range(0, upper):
        if i == next_square:
            next_square += diff
            diff += 2
            continue
        yield i

如果你想为每个完美正方形的数字做一些事情,那么发电机就更容易了:

(n * n for n in range(upper))

答案 14 :(得分:1)

此回复与您提出的问题无关,而是与我在您发布的代码中看到的隐含问题有关,即“如何检查某些内容是否为整数?”

你通常会得到的第一个答案是“不要!”而且在Python中,类型检查通常不是正确的做法。

但是,对于那些罕见的例外,不是在数字的字符串表示中查找小数点,而是要使用 isinstance 函数:

>>> isinstance(5,int)
True
>>> isinstance(5.0,int)
False

当然这适用于变量而不是值。如果我想确定是否为整数,我会这样做:

>>> x=5.0
>>> round(x) == x
True

但正如其他人已经详细介绍的那样,在大多数非玩具的例子中都会考虑浮点问题。

答案 15 :(得分:1)

  1. 决定号码的长度。
  2. 取delta 0.000000000000 ....... 000001
  3. 查看(sqrt(x))^ 2 - x是否大于/等于/小于delta并根据增量误差确定。

答案 16 :(得分:0)

@Alex Martelli解决方案的一种变体,没有set

x in seenTrue时:

  • 在大多数情况下,它是最后添加的内容,例如1022产生x的序列511、256、129、68、41、32, 31 31
  • 在某些情况下(例如,完美正方形的前身),它是倒数第二个,例如1023产生511、256、129、68、41, 32 ,31, 32

因此,只要当前x大于或等于前一个,就立即停止:

def is_square(n):
    assert n > 1
    previous = n
    x = n // 2
    while x * x != n:
        x = (x + (n // x)) // 2
        if x >= previous:
            return False
        previous = x
    return True

x = 12345678987654321234567 ** 2
assert not is_square(x-1)
assert is_square(x)
assert not is_square(x+1)

与原始算法的等效性测试为1

答案 17 :(得分:0)

a=int(input('enter any number'))
flag=0
for i in range(1,a):
    if a==i*i:
        print(a,'is perfect square number')
        flag=1
        break
if flag==1:
    pass
else:
    print(a,'is not perfect square number')

答案 18 :(得分:0)

这个想法是运行一个从i = 1到floor(sqrt(n))的循环,然后检查平方是否等于n。

bool isPerfectSquare(int n) 
{ 
    for (int i = 1; i * i <= n; i++) { 

        // If (i * i = n) 
        if ((n % i == 0) && (n / i == i)) { 
            return true; 
        } 
    } 
    return false; 
} 

答案 19 :(得分:0)

如果连续项从 n 的平方根以上开始,则可以通过观察连续项形成递减序列来改进巴比伦方法。

def is_square(n):
    assert n > 1
    a = n
    b = (a + n // a) // 2
    while b < a:
        a = b
        b = (a + n // a) // 2
    return a * a == n

答案 20 :(得分:0)

我不确定Python,但你可以这样做:

function isSquare(x) = x == floor(sqrt(x) + 0.5)^2

即,取一个数字,找到平方根,将其四舍五入到最接近的整数,将其平方,并测试它是否与原始数字相同。 (floor并添加0.5是为了防止由于浮点数学而导致sqrt(4)返回1.9999999...等情况,正如Mike Graham指出的那样。)

如果您感兴趣,曾经对Fastest way to determine if an integer’s square root is an integer进行过非常好的讨论。

编辑澄清。

答案 21 :(得分:-1)

a = math.sqrt(n)
b = int(a) 
a == b 

答案 22 :(得分:-3)

我使用巴比伦方法对原始解决方案略有改进。不是使用一组来存储每个先前生成的近似值,而是仅存储最近的两个近似值并针对当前近似值进行检查。这节省了浪费大量时间检查整个先前的近似值。我使用的是java而不是python和BigInteger类,而不是普通的原始整数。

    BigInteger S = BigInteger.ZERO;    
    BigInteger x = BigInteger.ZERO;
    BigInteger prev1 = BigInteger.ZERO;
    BigInteger prev2 = BigInteger.ZERO;
    Boolean isInt = null;

    x = S.divide(BigInteger.valueOf(2));

    while (true) {
        x = x.add(preA.divide(x)).divide(BigInteger.valueOf(2));
        if (x.pow(2).equals(S)) {   
            isInt = true;
            break;
        }

        if (prev1.equals(x) || prev2.equals(x)) {
            isInt = false; 
            break;
        }

        prev2 = prev1;
        prev1 = x;
    }

答案 23 :(得分:-4)

有一种非常简单的方法可以做到这一点。找出这个数字有多少个因素(包括一个和它自己)。如果它有一个奇数的因子,那就是一个正方形。

def getFactors(n):
    '''Code for counting factors of n.'''
    result = 1 # not forgetting to count the number itself
    for i in range(1, n // 2 + 1):
         if n % i == 0:
             result += 1
    return result

如果函数的结果是奇数,则为正方形。

编辑:

这可能不是计算机程序的最佳方法,但它对人类来说是一种很好的方法。