2

I have this python code:

def sqrt(x):
    ans = 0
    if x >= 0:
        while ans*ans < x:
            ans = ans + 1
            if ans*ans != x:
                print x, 'is not a perfect square.'
                return None
            else:
                print x, ' is a perfect square.'
                return ans
    else:
        print x, ' is not a positive number.'
        return None

y = 16      
sqrt(y)

the output is:

16 is not a perfect square.

Whereas this works perfectly:

x = 16
ans = 0
if x >= 0:
    while ans*ans < x:
        ans = ans + 1
        #print 'ans =', ans
    if ans*ans != x:
        print x, 'is not a perfect square'  
    else: print ans, 'is a perfect square'
else: print x, 'is not a positive number'

What am I doing wrong?

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
eozzy
  • 66,048
  • 104
  • 272
  • 428
  • 1
    Here is a related question on finding whether a number is a perfect square: http://stackoverflow.com/questions/295579/fastest-way-to-determine-if-an-integers-square-root-is-an-integer – Nick Craig-Wood Oct 10 '09 at 10:30

9 Answers9

10

Just thought I'd contribute a simpler solution:

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

This is valid for n < 2**52 + 2**27 = 4503599761588224.

Examples:

>>> is_square(4)
True
>>> is_square(123)
False
>>> is_square(123123123432**2)
True
Sunjay Varma
  • 5,007
  • 6
  • 34
  • 51
  • While a good answer for *small* values, this has precision problems. `is_square(123456789123456789**7-1)` gives `True`. There's no particularly easy solution, though. [I don't think `123123123432156156165**7` is square anyway.](http://www.wolframalpha.com/input/?i=is+123456789123456789**7+square). – Veedrac May 26 '14 at 07:17
  • and 123123123432**7 is not a perfect square: its sqrt lies between 654920651322780642131484946101910838253 and 654920651322780642131484946101910838254 – blabla999 Oct 27 '15 at 20:15
7

Indent your code correctly to let the while statement execute until ans*ans < x:

def sqrt(x):
    ans = 0
    if x >= 0:
        while ans*ans < x:
            ans = ans + 1

        if ans*ans != x:  # this if statement was nested inside the while
            print x, 'is not a perfect square.'
            return None
        else:
            print x, ' is a perfect square.'
            return ans
    else:
        print x, ' is not a positive number.'
        return None

y = 16          
print sqrt(y)

Try it out here.

Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • Aah! I was going crazy over this, indentation while really helps in reading the code can be really difficult to debug! :) – eozzy Oct 10 '09 at 06:49
  • 2
    Give me Python's indentation rules any day over the possibility my indentation may not match my braces in C et al. It's a lot easier if you make sure your editor is configured for spaces only. – paxdiablo Oct 10 '09 at 07:04
1

Your while loop only executes once. No matter which branch the if statement inside it takes, the whole function will return immediately.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
0

EDIT I modified it, tried it out, and it works. You just need this piece of code

As soon as ans = 4, ans * ans is no longer smaller than x. Try while ans*ans <= x: instead of just <

def sqrt(x):
ans = 0
if x >= 0:
        while ans*ans <= x:                     
                if ans*ans == x:
                            print x, ' is a perfect square.'
                            return ans
        else:
            ans = ans + 1
ManicMailman
  • 75
  • 2
  • 13
  • You can't return in your loop in the case where ans*ans is not x. def sqrt(x): ans = 0 if x >= 0: while ans*ans <= x: ans = ans + 1 if ans*ans == x: print x, ' is a perfect square.' return ans else: print x, ' is not a positive number.' return None print x, 'is not a perfect square.' return None y = 16 sqrt(y) – ManicMailman Oct 10 '09 at 06:27
0

Change your code so it displays the value of ans as well as x, so you can tell how many times the loop is executed.

pavium
  • 14,808
  • 4
  • 33
  • 50
0

If your code sample is actually correctly indentet the first round of the while will return on it's first round - always. So any positive value of x>1 will fullfil the ans*ans=1*1=1!=x, giving "x is not a perfect square".

You basically needs to get your indentation right - like you do in your other example. Again - if your code sample here actually is correctly indented. Try this:

def sqrt(x):
    ans = 0
    if x >= 0:
        while ans*ans < x:
            ans = ans + 1

        if ans*ans != x:
            print x, 'is not a perfect square.'
            return None
        else:
            print x, ' is a perfect square.'
            return ans
    else:
        print x, ' is not a positive number.'
        return None
stiank81
  • 25,418
  • 43
  • 131
  • 202
0
def isPerfectSquare(number):
    return len(str(math.sqrt(number)).split('.')[1]) == 1
trycatch22
  • 307
  • 4
  • 14
0

I think this is probably short.

 def issquare():
      return (m**.5 - int(m**.5)==0)
-1

If the goal is to determine whether a number is a perfect square, I would think it would be simpler (and perhaps more efficient) to use math builtins, e.g.:

def is_perfect_square(n):
  if not ( ( isinstance(n, int) or isinstance(n, long) ) and ( n >= 0 ) ):
    return False 
  else:
    return math.sqrt(n) == math.trunc(math.sqrt(n))
gumption
  • 1,108
  • 13
  • 10
  • 1
    This returns True for `(2**64) - 1` -- you're losing precision – bstpierre Apr 22 '11 at 13:45
  • 1
    Not relevant criticism, despite being true. This isnt a pure math page, this is a programming site. You cannot even store irrational numbers in computers. Precision is never infinite; thats the point of computers and anyone whose done any programming knows this ahead of time. Dont see a reason for criticizing. Numbers that large wont be tested except by mathematicians who probably have better notions and wont be on this site. – CogitoErgoCogitoSum Aug 17 '17 at 07:03