0

I wrote a function that returns whether a number input is a square or not

def is_square(n):
    if n<1:
        return False
    else:
        for i in range(int(n/2)+1):
            if (i*i)==n:
                return True
            else:
                return False

I am confident that this code works. But when I did the test cases, example:test.expect( is_square( 4)), it says that the value is not what was expected.

tristansokol
  • 4,054
  • 2
  • 17
  • 32
M. Abra
  • 91
  • 2
  • 5
  • 9

13 Answers13

14

Your function doesn't actually work, as it will immediatley return False on the first non-square-root found. Instead you will want to modify your code to be:

def is_square(n):
    if n<1:
        return False
    else:
        for i in range(int(n/2)+1):
            if (i*i)==n:
                return True
        return False

such that it only returns false once all possible square roots have been checked. You may also want to look into math.sqrt() and float.is_integer(). Using these methods your function would become this:

from math import sqrt

def is_square(n):
    return sqrt(n).is_integer()

Keep in mind that this method will not work with very large numbers, but your method will be very slow with them, so you will have to choose which to use.

BluCode
  • 1,097
  • 7
  • 16
  • 1
    `math.sqrt` is only approximate, like most floating-point operations. If you want to know whether an integer is a square, `math.sqrt` isn't an appropriate function to use. [Here's a demo of your `is_square` failing.](http://ideone.com/HFVT4H) – user2357112 Jun 13 '17 at 20:50
  • W.R.T the first command in your code: Do you think 0 is not a square? I agree we can decide that negative numbers are irrelevant, but *if* someone asks whether a negative number is a square, then don't they tacitly imply that they are considering Gaussian (= complex) integers? – Max Mar 22 '22 at 05:06
9

To stick to integer-based algorithms, you might look at implementation of binary search for finding square root:

def is_square(n):
    if n < 0:
        return False
    if n == 0:
        return True
    x, y = 1, n
    while x + 1 < y:
        mid = (x+y)//2
        if mid**2 < n:
            x = mid
        else:
            y = mid
    return n == x**2 or n == (x+1)**2
enedil
  • 1,605
  • 4
  • 18
  • 34
6

The main idea of Python philosophy is to write simple code. To check if a number is an perfect square:

def is_square(n):
    return n**0.5 == int(n**0.5)

When power to a float you can find the root of a number.

Manu
  • 112
  • 4
  • 7
    This loses precision once your numbers get truly large: `is_square(67108864**2 + 1)` yields `True`. – TemporalWolf Jun 13 '17 at 21:57
  • @TemporalWolf Quote from [micsthepick] (https://stackoverflow.com/a/37197669/8156982) _if you want to check ridiculously large cases, you should use a Babylonian algorithm approach, but this is fine for simple cases like finding the number of perfect squares below 1 million or another similar case with a brute-force algorithm._ – Manu Jun 14 '17 at 15:57
  • 1
    There is nothing necessarily wrong about this approach, but I'm a fan of acknowledging limits up front. – TemporalWolf Jun 14 '17 at 16:51
4

In Python 3.8+, use this:

def is_square(n):
    root = math.isqrt(n)
    return n == root * root
Dennis
  • 2,249
  • 6
  • 12
1

You can simply use simpy module import it as,

from sympy.ntheory.primetest import is_square 

and you can check for a number like this:

is_square(number) 

It will return a boolean value

Joe Ferndz
  • 8,417
  • 2
  • 13
  • 33
Shreya
  • 63
  • 6
  • 2
    This should be the way to go, but that library function, in addition to its cryptic and illogical location (it shouldn't be within "primetest"), is horrible bloatware: besides endless `int()` and `as_int()` conversions, it goes through `sympy.core.power.integer_nthroot` which in spite of its name uses floating point arithmetics in `isqrt_small_python` called by `sqrtrem_python`... and look at the code there... – Max Mar 22 '22 at 04:29
0

I think the best take, using only "built-in" integer arithmetic, is:

def issquare(n): return math.isqrt(n)**2==n

(Squares x**2 are a priori more efficiently computed than products x*x...)

According to my timings, this is (at least up to ~ 10^8) faster than sympy.numtheory.primetest.is_square.

(I use a different name to make it easier to compare the two.) The latter is first using some modular checks that should speed it up considerably, but it has so much conversion and testing overhead (int, as_int, squares become n-th powers with n=2, integers are converted from "small" to multiprecision integers and back, ...) that all the advantage is lost. After a lot of tests, it roughly does the above, using ntheory.nthroot, which is again an overkill: designed for any n-th root, the square root is just one special case, and noting is optimized for this case. Some subroutines there even do very weird floating point arithmetics including multiplication with 1.0000000001 and similar horrors... I once got the following horrible error message: (The original output has the full path "C:\Users\Username\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\" instead of each "..." below...)

  File "...\sympy\ntheory\primetest.py", line 112, in is_square
    return integer_nthroot(n, 2)[1]
  File "...\sympy\core\power.py", line 86, in integer_nthroot
    return _integer_nthroot_python(y, n)
  File "...\sympy\core\power.py", line 94, in _integer_nthroot_python
    x, rem = mpmath_sqrtrem(y)
  File "...\mpmath\libmp\libintmath.py", line 284, in sqrtrem_python
    y = isqrt_small_python(x)
  File "...\mpmath\libmp\libintmath.py", line 217, in isqrt_small_python
    r = int(x**0.5 * 1.00000000000001) + 1
KeyboardInterrupt

This gives a good idea of the abyss into which sympy's is_square hopelessly drowns...

Documentation: see is_square in Sympy's Ntheory Class Reference

P.S.: FWIW, regarding other answers suggesting to use round() etc, let me just mention here that ceil(sqrt(n))**2 < n (!!), for example when n is the 26th and 27th primorial -- not extremely large numbers! So, clearly, use of math.sqrt is not adequate.

Max
  • 415
  • 5
  • 12
-1
def myfunct(num):
    for i in range(0,num):
        if i*i==num:
            return 'square'
    else:
        return 'not square'
סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68
Ajith
  • 1
  • 2
    While this code may answer the question, providing additional context regarding **how** and **why** it solves the problem would improve the answer's long-term value. – Alexander Mar 10 '18 at 17:23
-1

Easiest working solution, but not for large numbers.

def squaretest(num):
    sqlist=[]
    i=1
    while i**2 <= num:
        sqlist.append(i**2) 
        i+=1
    return num in sqlist
Souvikavi
  • 108
  • 1
  • 10
-1

Assuming that n >= 0:

def is_square(n):
    tmp = int(n ** 0.5)
    return n == tmp * tmp
          
print(is_square(81), is_square(67108864 ** 2 + 1))  # True False
Tomer Shetah
  • 8,413
  • 7
  • 27
  • 35
Lucek008
  • 1
  • 1
-2

Another approach:

    def SQRT(x):
        import math
        if math.sqrt(x) == int(math.sqrt(x)):
            return True
        else:
            return False
  • 1
    This is very bad! Do not suggest such things to other users if you only think but do not really know what it does. `round(sqrt())` most often does *not* give the result you want! You may check that often, even ceil(sqrt(n))**2 is *smaller* (!!) than n -- e.g., when n is the product of the first 26 prime numbers. (Don't forget that almost all numbers are larger than that!) – Max Mar 22 '22 at 05:01
  • I'm not sure I quite understand what you mean. I changed round() to int() as I do think that is more appropriate. But how is checking if the sqrt() == int(sqrt()) not a good approach? If they are not equal, then x wasn't a square. – Griffin McKnight Mar 23 '22 at 17:20
-2
def is_square(n):
    if n < 0:
        return False
    return round(n ** 0.5) ** 2 == n
Asclepius
  • 57,944
  • 17
  • 167
  • 143
Groovy Guevara
  • 371
  • 3
  • 4
-3

To check if a number is a square, you could use code like this:

import math
number = 16
if math.sqrt(number).is_interger:
        print "Square"
else:
        print "Not square"

import math imports the math module.

if math.sqrt(number).is_interger: checks to see if the square root of number is a whole number. If so, it will print Square. Otherwise, it will print Not square.

anonymous
  • 271
  • 3
  • 16
-3

Since math.sqrt() returns a float, we can cast that to a string, split it from "." and check if the part on the right(the decimal) is 0.

import math
def is_square(n):
x= str(math.sqrt(n)).split(".")[1]  #getting the floating part as a string.
return True if(x=="0") else False