找出一个数字是否是一个完美的正方形

时间:2015-05-26 01:11:49

标签: python math

我试图编写一个程序来查找0到100之间的数字n,这样n! + 1是一个完美的正方形。我试图这样做是因为我知道只有三个这样做是为了测试我的Python能力 - 我失败了因为我真的无法做到。

4 个答案:

答案 0 :(得分:5)

math.sqrt总是会返回float,即使这个浮点数恰好是4.0。正如文档所说,“除非另有明确说明,否则所有返回值都是浮点数。”

所以,你对type(math.sqrt(x)) == int的测试永远不会成真。

您可以尝试通过检查float是否表示整数来解决这个问题,如下所示:

sx = math.sqrt(x)
if round(sx) == sx:

甚至a built-in method甚至可以做到这一点:

if sx.is_integer():

但请记住,float值不是实数的完美表示,并且总是有舍入问题。例如,对于数字太大,sqrt可能舍入为整数,即使它实际上不是一个完美的正方形。例如,如果math.sqrt(10000000000**2 + 1).is_integer()True,即使数字显然不是一个完美的正方形。

我可以告诉你这是否在你的价值范围内是安全的,但你能说服自己吗?如果没有,你不应该只是假设它是。

那么,有没有办法检查不受float道路问题的影响?当然,我们可以使用整数运算来检查:

sx = int(round(math.sqrt(x)))
if sx*sx == x:

但是,正如Stefan Pochmann指出的那样,即使这项检查是安全的,这是否意味着整个算法是?没有; sqrt本身可能已经四舍五入到你丢失整数精度的程度。

所以,你需要一个确切的sqrt可以通过使用具有巨大配置精度的decimal.Decimal来实现此目的。这将需要一些工作和大量的内存,但它是可行的。像这样:

decimal.getcontext().prec = ENOUGH_DIGITS
sx = decimal.Decimal(x).sqrt()

ENOUGH_DIGITS有多少位数?那么,您需要多少位数来代表100!+1

所以:

decimal.getcontext().prec = 156
while n <= 100:
    x = math.factorial(n) + 1
    sx = decimal.Decimal(x).sqrt()
    if int(sx) ** 2 == x:
        print(sx)
    n = n + 1

如果您考虑一下,有一种方法可以将所需的精确度降低到79位数,但我会把它作为读者的练习。

你可能假设解决这个问题的方法是使用纯粹的整数数学。例如,你可以通过使用Newton's method来确定整数是否是对数时间的平方,直到你的近似误差小到足以检查两个边界整数。

答案 1 :(得分:3)

对于非常大的数字,最好完全避免使用浮点平方根,因为你会遇到太多精度问题而你甚至无法保证你将在正确答案的1整数值范围内。幸运的是,Python本身支持任意大小的整数,因此您可以编写一个整数平方根检查函数,如下所示:

def isSquare(x):
    if x == 1:
        return True
    low = 0
    high = x // 2
    root = high
    while root * root != x:
       root = (low + high) // 2
       if low + 1 >= high:
          return False
       if root * root > x:
          high = root
       else:
          low = root
    return True

然后你可以像这样运行从0到100的整数:

n = 0
while n <= 100:
    x = math.factorial(n) + 1
    if isSquare(x):
        print n
    n = n + 1

答案 2 :(得分:1)

这是另一个只使用整数的版本,通过增加2的递减幂来计算平方根,例如intsqrt(24680)将被计算为128 + 16 + 8 + 4 + 1。

 def intsqrt(n):
    pow2 = 1
    while pow2 < n:
        pow2 *= 2
    sqrt = 0
    while pow2:
        if (sqrt + pow2) ** 2 <= n:
            sqrt += pow2
        pow2 //= 2
    return sqrt

factorial = 1
for n in range(1, 101):
    factorial *= n
    if intsqrt(factorial + 1) ** 2 == factorial + 1:
        print(n)

答案 3 :(得分:0)

math.sqrt返回的数字永远不是int,即使它是一个整数。How to check if a float value is a whole number