Finding if n! + 1 is a perfect square

◇◆丶佛笑我妖孽 提交于 2021-01-29 03:30:44

问题


I'm trying to write a program to look for a number, n, between 0 and 100 such that n! + 1 is a perfect square. I'm trying to do this because I know there are only three so it was meant as a test of my Python ability.

Refer to Brocard's problem.


回答1:


For very large numbers it's better to avoid using floating point square roots altogether because you will run into too many precision issues and you can't even guarantee that you will be within 1 integer value of the correct answer. Fortunately Python natively supports integers of arbitrary size, so you can write an integer square root checking function, like this:

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

Then you can run through the integers from 0 to 100 like this:

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



回答2:


math.sqrt always returns a float, even if that float happens to be, say, 4.0. As the docs say, "Except when explicitly noted otherwise, all return values are floats."

So, your test for type(math.sqrt(x)) == int will never be true.

You could try to work around that by checking whether the float represents an integer, like this:

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

There's even a built-in method that does this as well as possible:

if sx.is_integer():

But keep in mind that float values are not a perfect representation of real numbers, and there are always rounding issues. For example, for a too-large number, the sqrt might round to an integer, even though it really wasn't a perfect square. For example, if math.sqrt(10000000000**2 + 1).is_integer() is True, even though obviously the number is not a perfect square.

I could tell you whether this is safe within your range of values, but can you convince yourself? If not, you shouldn't just assume that it is.

So, is there a way we can check that isn't affected by float roading issues? Sure, we can use integer arithmetic to check:

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

But, as Stefan Pochmann points out, even if this check is safe, does that mean the whole algorithm is? No; sqrt itself could have already been rounded to the point where you've lost integer precision.

So, you need an exact sqrt. You could do this by using decimal.Decimal with a huge configured precision. This will take a bit of work, and a lot of memory, but it's doable. Like this:

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

But how many digits is ENOUGH_DIGITS? Well, how many digits do you need to represent 100!+1 exactly?

So:

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

If you think about it, there's a way to reduce the needed precision to 79 digits, but I'll leave that as an exercise for the reader.


The way you're presumably supposed to solve this is by using purely integer math. For example, you can find out whether an integer is a square in logarithmic time just by using Newton's method until your approximation error is small enough to just check the two bordering integers.




回答3:


Here's another version working only with integers, computing the square root by adding decreasing powers of 2, for example intsqrt(24680) will be computed as 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)



回答4:


The number math.sqrt returns is never an int, even if it's an integer.How to check if a float value is a whole number



来源:https://stackoverflow.com/questions/30447975/finding-if-n-1-is-a-perfect-square

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!