我怎么能检查一个数字是一个完美的广场?

我怎么能检查一个数字是一个完美的广场?

目前来说,速度无关紧要。

依赖任何浮点运算( 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) 

提示:它是基于平方根的“巴比伦algorithm”,参见维基百科 。 它适用于任何你有足够的内存进行计算的正数,以完成;-)。

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

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

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

 152415789666209426002111556165263283035677489 True 152415789666209426002111556165263283035677490 False 

请在根据浮点中间结果提出解决scheme之前,确保它们在这个简单的例子中正确工作 – 这并不困难(只需要一些额外的检查,以防sqrt计算结果稍微偏离),只需要一个一点关心。

然后尝试用x**7find巧妙的方法来解决你会遇到的问题,

 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的情况下,速度很快; – )…

用牛顿的方法快速调入最接近的整数平方根,然后将其平方,看看它是否是你的数字。 见isqrt 。

由于在处理浮点计算时(例如这些计算平方根的方法),您决不可能依赖精确的比较,所以不太容易出错的实现

 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取最低值,首先将float值增加0.5意味着如果我们处于一个范围内, float仍然有足够精细的分辨率来表示附近的值我们在看。

 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并打印出“这不是一个完美的方形”。

我是Stack Overflow的新手,并且快速浏览一下以find解决scheme。 我刚刚在另一个线程上发现了一些上面的例子( find完美的方块 ),并认为我会在这里发布一些细微的变化(使用nsqrt作为临时variables),以防感兴趣/使用:

 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) 

这可以通过使用decimal模块来解决,以获得任意精度的平方根,并且容易检查“正确性”:

 import math from decimal import localcontext, Context, Inexact def is_perfect_square(x): # If you want to allow negative squares, then set x = abs(x) instead if x < 0: return False # Create localized, default context so flags and traps unset with localcontext(Context()) as ctx: # Set a precision sufficient to represent x exactly; `x or 1` avoids # math domain error for log10 when x is 0 ctx.prec = math.ceil(math.log10(x or 1)) + 1 # Wrap ceil call in int() on Py2 # Compute integer square root; don't even store result, just setting flags ctx.sqrt(x).to_integral_exact() # If previous line couldn't represent square root as exact int, sets Inexact flag return not ctx.flags[Inexact] 

为了展示真正的巨大价值:

 # 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 

如果你增加被testing值的大小,最终会变得很慢(对于一个200,000位的方块来说,接近一秒),但是对于更温和的数字(比如说20000位),它仍然比人们注意到的要快个人价值观(我的机器〜〜33毫秒)。 但是由于速度并不是你最关心的问题,所以这是用Python的标准库来完成的好方法。

当然,使用gmpy2会更快,只要testinggmpy2.mpz(x).is_square() ,但如果第三方软件包不是你的东西,上面的工作就很好。

你可以二进制search圆angular的平方根。 将结果平方以查看它是否与原始值匹配。

用FogleBirds的答案你可能会更好 – 虽然要小心,因为浮点算术是近似的,可以抛弃这种方法。 你原则上可以从一个比完美平方更大的整数中得到一个假的正数,例如,由于失去了精度。

  1. 决定这个号码会有多长。
  2. 采取一个三angular形0.000000000000 ……. 000001
  3. 查看(sqrt(x))^ 2 – x是否大于/等于/小于delta,并根据delta误差来决定。

这个回应与你所说的问题无关,但是对于我在你发布的代码中看到的一个隐含的问题,即“如何检查是否是一个整数?

你通常会回答这个问题的第一个答案是“不要!” 确实,在Python中,types检查通常是不正确的。

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

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

当然这适用于variables而不是价值。 如果我想确定是一个整数,我会这样做:

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

但是,正如其他人已经详细介绍的那样,在这类事情的大部分非玩具例子中都有浮点问题需要考虑。

如果你想遍历一个范围,并为每个不是完美的方格的数字做点事情,你可以这样做:

 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)) 

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

 def isSquare(n): ## Trivial checks if n != n//1: return False if n < 0: return False if n < 2: return True ## Reduction by powers of 4 with bit-logic while n&65535 == 0: n=n>>16 if n&255 == 0: n=n>>8 if n&15 == 0: n=n>>4 if n&3 == 0: n=n>>2 if n==1: return True ## even power of 2 ## Simple bit-logic test. if n&7 != 1: return False ## Simple modulo equivalency test if n % 10 in [2, 3, 7, 8]: return False ## Not 1,4,5,6,9 in mod 10 if n % 3 == 2: return False ## Not 0,1 mod 3 if n % 7 in [3, 5, 6]: return False ## Not 1,2,4 mod 7 ## Factor out the squares of small primes, if possible. ## Simple factor-quantity test. ## Also ensures coprimality for the Jacobi test. ps = [3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, \ 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 ] # 3 to 97 for i in ps: while n%(i*i)==0: n = n // (i*i) if n%i == 0: # odd power of a factor return False if n==1: return True # even power of small primes # The jacobi symbol (n / i). Easy, fast algorithm. Uses bit operations. # for i relatively prime to n, if ever -1, verified non-square. for i in ps: if jacobi(n,i) == -1: return False ## jacobi non-square ## Babylonian Algorithm. Finding the integer square root. x = n // 2 A = [x, n] while x * x != n: x = (x + (n // x)) // 2 if x in A: return False A += [x] return True 

非常直截了当。 首先它检查我们有一个整数,并在那个正整数。 否则没有意义。 它让0和1滑落为真(不知道是否有必要,但更早的实现在这些值失败)。

下一个代码块使用位移和位逻辑操作,以非常快的子algorithm系统地去除4的幂。 如果可能的话,我们最终没有find原来的n的isSquare,而是一个k <n的isSquare,这个k已经被4的幂数缩小了。

第三块代码执行简单的布尔位逻辑testing。 任何完美平方的最不重要的三位数是001.总是。 除了权力4导致的零,无论如何,这已经占了。 如果testing失败,你马上知道它不是一个正方形。 如果它通过,你不能确定。

像第三个方块一样,第四个方法用简单的模数运算符来testing十进制的位置值,并且倾向于捕获通过前一个testing的值。 另外一个mod 3和mod 7testing。

第五块试图分解所有小于100的小数的平方。减less数量的大小,是一个相对简单的检查。 无论如何,这个位对于下一个代码是必需的。

第六块代码是对雅可比符号的调用,并且与二次残差有关。 它使用前面代码块中使用的主要列表作为基本值。 前面的分块因子是必要的,因为我们需要雅可比testing的互质关系才有价值。

最后,第七块代码非常类似于顶级答复者 – Alex Martelli – 的答案。 基本上使用古巴比伦algorithmfind平方根,但将其限制为整数值而忽略浮点。 为了速度和扩大可testing的值的大小,都要做好。

有趣的是,在前1500万(至less)正整数,我的代码从来没有得到这么多。 我几乎不必强迫非方形的平方根。 事实上,我不能完全确定我曾经有过。 这段代码唯一的一次贯穿 – 根据我的经验 – 当我有一个完美的方形时。 所以我几乎可以跳过它,并返回一个非常可能的真实。

顺便说一下,我testing了Alex Martelli推荐的testing编号,以及几个数量级的大小。

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

打印结果如下:

  True False 

它在0.8秒内完成了。

在我看来,我的algorithm和Alex Martelli的algorithm一样,具有所有的好处,但是还有一个额外的好处,即通过4次幂乘以琐碎的检查来减小大小,这提高了速度,效率,准确性和数字大小是可testing的。 在非Python实现中可能尤其如此。 然后,它还执行另一个简单的布尔逻辑testing,在甚至将自己的问题转​​移到更复杂或计算成本更高的算术方法之前,几乎立即将其余8个中的7个作为明确的非方块移除等等。

这并不是说我的方法更好。 我将计算时间与巴比伦方法本身进行了比较,并对我的全部函数进行了比较,实际情况是有时直的平方根计算速度要快得多,有时它的速度要慢得多。 就像我以前说过的,我没有理由实际运行该函数的平方根计算部分。 这是为了保险,但我有有效的结果,不负责任的大数字。 虽然我的algorithm本身有时候是巴比伦algorithm的两倍,但是如果你把巴比伦人剪出来的话,在这种情况下几乎可以把运行时间减半。

Jacobi

 def jacobi(m=5, n=0): ## (m / n) n = int(n//1) m = int(m//1) if m == 0: if n==1: return 1 return 0 elif m == 1: return 1 elif m == 2: return 1 if (n&7) in (1,7) else -1 elif m&1 == 0: return jacobi(2,n) * jacobi(m/2, n) elif n < m: return jacobi(m%n, n) elif m&3 == 3 and n&3 == 3: return -jacobi(n, m) else: return jacobi(n, m) 

此外,Jacobi和小素数的分解也可能是可以忽略的。 我特别推荐它,如果你的isSquare的目的是首先find素数 – 不需要循环推理。

我不确定Python,但你可以做一些事情:

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

也就是说,取一个数字,find平方根,将其四舍五入到最接近的整数,将其平方,并testing它是否与原始数字相同。 (正如Mike Graham所指出的那样,为了防止像sqrt(4)返回1.9999999...由于浮点math问题, floor0.5被完成。)

如果你有兴趣,有一次很好的讨论, 以确定一个整数的平方根是一个整数 。

编辑澄清。

这是我的方法

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

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

我认为这个工作很简单:

 from math import sqrt def is_perfect_square(num): return int(sqrt(num)) == sqrt(num) 

这在数字上就像你可能拥有的解决scheme一样天真。 它适用于小数目。

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

很明显,它失败了很多,如152415789666209426002111556165263283035677490。

我的答案是:

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

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

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

有一个非常简单的方法来做到这一点。 找出这个数字有多less个因素(包括一个和它本身)。 如果它有一个奇数的因素,这是一个正方形。

 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 

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

编辑:

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

使用巴比伦方法,我对原始解决scheme略有改进。 不是使用一个集合来存储每个先前生成的近似值,而是只存储最近的两个近似值,并根据当前的近似值进行检查。 这节省了大量的时间浪费检查整个先前的近似集。 我使用的是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; } 
Interesting Posts