1

I'm attempting to return a True/False output based on whether numbers in a list are square numbers or not.

The list will need to be checked several times and the list can be any positive integer which means the integer can be very large, in fact, too large for the use of other solutions involving math.sqrt() functions which produce an overflow error shown here:

userList = [1*10**1000]
print ([x for x in userList if math.sqrt(x).is_integer()])

>>>Traceback (most recent call last):
print ([x for x in userList if math.sqrt(x).is_integer()])
OverflowError: int too large to convert to float

Here is my* method:

def squares():
    for i in userList:
        if i in squares: #the list in which all the square numbers are stored
            return True
        else:
            return False

*My current idea is pre-preparing square numbers into a separate list in order to compare them but I am looking for, perhaps, an alternative, faster method as the userList can become very large.

I want to store the returned output in a separate list as so:

out = []
for i in userList:
    out.append(squares())

print(out)
>>>[False,True...]

As you can see this will take a long time when dealing with many numbers and that is the reason as to why I require a faster method.

  • look up if the squareroot is an integer ? or is this some kind of hackerrank coding challenge where the lists are so big this wont fly? Edit: for checking you need a `set` - not a list – Patrick Artner Jun 09 '18 at 19:07
  • and if you don't going to have this number...I think the best way is to run an algorithm that check it. the naive way is to run all the number until his root and check – Green Jun 09 '18 at 19:08
  • 1
    "pre-preparing square numbers into a separate list " Don't do that. If you want a container for efficient membership testing, use a `set`, which has constant time membership checking versus a `list`, which has linear time membership testing. – juanpa.arrivillaga Jun 09 '18 at 19:09
  • Possible duplicate: [Check for perfect squares in a list](https://stackoverflow.com/questions/42850184/check-for-perfect-squares-in-a-list) – jpp Jun 09 '18 at 19:12
  • The numbers in the list can be any positive integer and may be too large for sqrt to handle. There will be many checks involved with many possible values @RoryDaulton – TrojanHorse Jun 09 '18 at 19:12
  • If the input might be any positive integer, it is not practical to have all of the square numbers in a list. It certainly wouldn't be fast to search the list. – khelwood Jun 09 '18 at 19:17
  • @PatrickArtner ah yes a set is required, im new to python so am finding it quite difficult to adapt – TrojanHorse Jun 09 '18 at 19:21
  • 1
    Now that the OP has made some clarifications, this question is **not a duplicate** of the other question. Three of its answers use floating-point arithmetic, which will not suffice for this question since the integers may be too large to fit into a float variable. The one answer that avoids this uses a tremendously slow algorithm to find the integer part of the square root. We should reopen this question, or close it for other reasons. – Rory Daulton Jun 09 '18 at 19:24
  • @jpp as RoryDaulton has conveyed, the question is **not a duplicate** because the answers use floating-point arithmetic, which may prevent larger integers to fit into a float variable and the only other answer uses "a tremendously slow algorithm", too slow for a large list and the questions demands – TrojanHorse Jun 09 '18 at 19:35
  • @TrojanHorse, In that case, you need be very explicit in your question that's the problem. Give a concrete reproducible example. Show us that it doesn't work. Then we can suggest other approaches. Until then, this is a duplicate. – jpp Jun 09 '18 at 19:36
  • @jpp I have updated the question clearly indicating that solutions involving floating point arithmetic cannot be a solution for this answer and that program speed is a primary factor for this questions demands – TrojanHorse Jun 09 '18 at 19:59
  • 1
    @TrojanHorse, Still needs an example... – jpp Jun 09 '18 at 20:04
  • If you give an example, this question is more likely to be reopened. For example, give a *short* list of big numbers, then show the exact output you want from that input. (One `True` or `False`, or a list of them, or other?) – Rory Daulton Jun 10 '18 at 23:01
  • 1
    @jpp an example has been presented – TrojanHorse Jun 11 '18 at 17:26
  • Try `x*0.5` instead of `math.sqrt(x)`. (I don't know, this might still result in the same error) – charlie Jun 11 '18 at 19:16
  • @LEEE the same error occurs unfortunately – TrojanHorse Jun 11 '18 at 19:54
  • 1
    Write a function to compute integer square roots. Newton's method can be used (with care). A simple binary search is even easier to implement and gives decent performance, even for large numbers. – John Coleman Jun 12 '18 at 16:54
  • @JohnColeman how would i go about writing said function – TrojanHorse Jun 13 '18 at 15:31

1 Answers1

4

A straightforward way is to write an integer square root function. Here is a sub-optimal (but still reasonably quick) way based on binary search:

def is_sqrt(m,n):
    return m**2 <= n < (m+1)**2

def isqrt(n):
    low = 0
    high = n
    m = (low + high)//2

    while not is_sqrt(m,n):
        if m**2 < n: #too small! must be in [m+1,high]
            low = m+1
        else: #too big! must be in [low, m-1]
            high = m - 1
        m = (low + high) // 2
    return m

def is_square(n):
    return n == (isqrt(n))**2

Then the following are almost instantaneous:

>>> is_square(77**200)
True
>>> is_square(77**200 + 1)
False
John Coleman
  • 51,337
  • 7
  • 54
  • 119
  • This works pretty fast, even for the largest exponent of a double precision float (2**1024) which math.sqrt() could not do! @johncoleman – TrojanHorse Jun 13 '18 at 17:36