2

Im trying to check is the number passed is a valid perfect square by

return True if(math.sqrt(num)%2 == 0 or \
              (math.sqrt(num)+1) % 2 == 0 ) else False

I want to know if I could write this better by breaking the if statement into two parts like

return True if(math.sqrt(num)%2 == 0) 
            elif ((math.sqrt(num)+1) % 2 == 0 ) 
            else False

Could someone help me with how to use elif here or if there is a better approach.

Thank you.

Prune
  • 72,213
  • 14
  • 48
  • 72
Tarun Kolla
  • 578
  • 5
  • 22
  • 4
    Don't use inline if statements if they are going to be very complicated. Use full if statements with blocks... – Andrew Li Sep 14 '18 at 00:09
  • 2
    Can't you just write `return (math.sqrt(num)%2 == 0 or (math.sqrt(num)+1) % 2 == 0)`? – Carcigenicate Sep 14 '18 at 00:09
  • Yes i can just write `return (math.sqrt(num)%2 == 0 or (math.sqrt(num)+1) % 2 == 0)` but i want to break this as I don't have to compute the or case if the first one is true. – Tarun Kolla Sep 14 '18 at 00:14
  • That isn't a reliable test. It would call `1 + math.factorial(25)` a perfect square even though it is manifestly not. – John Coleman Sep 14 '18 at 00:16
  • @Tarun Run `def f(x): print(x); return x;` `f(True) or f(False);`. `False` won't be printed. `or` short circuits. – Carcigenicate Sep 14 '18 at 00:18
  • @John I realized that after "Prune" mentioned it below in his answer. Thank you – Tarun Kolla Sep 14 '18 at 00:23
  • @Carcigenicate Thank you. That was helpful. – Tarun Kolla Sep 14 '18 at 00:24
  • The test works well for small numbers. For sufficiently large integers, anything involving `math.sqrt` will be unreliable. It is non-trivial to write a perfect square checker for big ints. – John Coleman Sep 14 '18 at 00:24
  • For what seems to be a homework question, there is little reason to worry too much about the issue, but the most reliable way to check would be to use an [integer square root](https://stackoverflow.com/q/15390807/4996248) algorithm which can work with arbitrary size integers. – John Coleman Sep 14 '18 at 00:31
  • I know this is an old question, but I randomly stumbled upon it and noticed something that wasn't mentioned: the duplicated `sqrt()` call. This isn't the point of this question, but I just wanted to mention it. Calling `sqrt` twice on the same value will be pretty inefficient as `num` gets big. Storing it in a variable instead (e.g. `s = math.sqrt(num)`, and using `s`) would double the speed in the `sqrt + 1 mod 2` test cases. – Starwarswii Sep 03 '20 at 04:41

5 Answers5

4

No need to use if statements at all

return math.sqrt(num) % 2 == 0 or (math.sqrt(num)+1) % 2 == 0 
Sean Peters
  • 328
  • 1
  • 7
  • These type of codes are hard to read and are prone to unintended consequences. Although python interpreter doesn't need if, humans do. –  Sep 14 '18 at 00:22
  • 1
    Sure for some stuff but this is a pretty straightforward and easy to read statement. All the extra syntax in other answers just makes it harder to read. – mschuett Sep 14 '18 at 03:32
  • 1
    The ternary if statement adds an extra layer of indirection which in my opinion makes it harder to read. If the complexity of the boolean equation becomes too large for a single line (I don't think that's the case here), my first step would be to seperate that equation into variables e.g. a = math.sqrt(num) % 2 == 0 b = (math.sqrt(num)+1) % 2 == 0 return a or b It'd have to be a rather large boolean equation for me to resort to an if, and I would never use a ternary if. – Sean Peters Sep 14 '18 at 04:30
2

First of all, there is no elif in the ternary operator. Second, your elif doesn't specify a return value (one reason it was left out of the ternary expression). Third, your check for the root being an integer is susceptible to round-off error. Instead, try rounding teh root to an integer, square that, and compare against the original value.

Prune
  • 72,213
  • 14
  • 48
  • 72
2

Simple one-liner with readability in mind.

def check(num): 
    return True if math.sqrt(num) % 2 == 0 or (math.sqrt(num)+1) % 2 == 0 else False

Result

>>> check(25)
True
>>> check(23)
False
  • 1
    You and I differ on "readability". I find this redundant, and thus *distracting* from readability. I'm not saying you're wrong, just that we differ. When I see something like this, I have to take time to see what the coder intended that could *not* be handled with the expression itself. – Prune Sep 14 '18 at 15:58
  • @Prune I think we are not that different. I too look for exceptions in the expression. The reason that I think this is more readable is it *clearly* states the return values for the values that match the expression, and value that does not match the expression. –  Sep 14 '18 at 16:16
1

Just answering your question on how to use elif and do it in more than a single line by breaking the if statement. I assume you put these in a function. There could be better ways though as pointed out in other answers

def check_sqrt(num):
    if math.sqrt(num)%2 == 0:
        return True
    elif (math.sqrt(num)+1) % 2 == 0:
        return True
    else:
        return False

print (check_sqrt(23))   
> False 
print (check_sqrt(25))
> True  
Sheldore
  • 32,099
  • 6
  • 34
  • 53
1

You should always write clearer code that everyone could understand. And you should make it a habit.

if math.sqrt(num)%2 == 0:
    return True
if (math.sqrt(num)+1) % 2 == 0:
    return True
return False
Tianxin Xie
  • 93
  • 1
  • 10