How can I golf this code to count all perfect squares below 100?

6

I'm trying to strip down my python code to be as few lines as possible. The task: count how many square numbers are below 100. Here's my code so far:

m = 0
for x in range(0, 100):
    m+=1-(-((-((x+1)**(0.5)-((x+1)**(0.5))//1))//1));
print(m)

That addition statement adds 1 to m (the counter) only when (x+1) is a perfect square. Is it possible to shorten anything? Maybe find a way to print without using a counter -- such as printing a summation in a form such as:

print(sum(min,max,variable,statement))

Graviton

Posted 2017-04-07T03:20:33.900

Reputation: 2 295

9print(9) works :P – ASCII-only – 2017-04-07T03:33:29.533

10To close voters: [tips] are on topic. – Rɪᴋᴇʀ – 2017-04-07T03:34:51.027

I mean, you can get rid of the semicolon on your third line. – Ben Frankel – 2017-04-07T03:35:35.827

1You say you want to count how many square numbers are below 100, but you're counting how many are between 1 and 100 inclusive. Which is it? – Ben Frankel – 2017-04-07T03:42:28.333

4

Have you taken a look at out Python golf tips? In particular, there's some easy gains from removing whitespace and parentheses. I think asking for particular advice for this particular golf is putting the cart before the horse.

– xnor – 2017-04-07T03:45:07.663

You could quite easily do print(int(100**0.5))... – HyperNeutrino – 2017-04-07T03:52:07.383

@Riker, "That addition statement adds 1 to m (the counter) only when (x+1) is a perfect square." – Ben Frankel – 2017-04-07T03:53:58.653

@Ben oh, didnt see that. Sorry. – Rɪᴋᴇʀ – 2017-04-07T03:56:20.183

Answers

3

For the exact question posed: since we know that 1 is a perfect square and all integers between that and the maximal one (here 9) will be included we can simply find that maximal one:

print((100-1)**.5//1)

(//1 performing integer division by one to remove any fractional part may be replaced with /1 prior to Python 3.)

with both endpoints (an inclusive start and exclusive stop equivalent to a range) this could be extended to a function (negative inputs catered for with max):

f=lambda start, stop:print(max(0,stop-1)**.5//1-max(0,start)**.5//1)

Jonathan Allan

Posted 2017-04-07T03:20:33.900

Reputation: 67 804

Ah, that's a good bit of math to solve the problem. Well done. – Graviton – 2017-04-07T04:12:47.657

2

For the record, below is another approach using additions and multiplications only.

The square of N is the sum of the N first odd positive integers:

1^2 = 1
2^2 = 1 + 3 = 4
3^2 = 1 + 3 + 5 = 9
4^2 = 1 + 3 + 5 + 7 = 16
etc.

Consequently, if we are to compute all perfect squares up to a given limit, each one can be quickly deduced from the previous one.

Hence the following possible algorithms:

# with 3 variables, using addition only
s = i = 1
n = 0

while s < 100:
  n += 1
  i += 2
  s += i

print(n)
# with 2 variables, using addition and multiplication
s = 1
n = 0

while s < 100:
  n += 1
  s += n * 2 + 1

print(n)

Or as a recursive lambda:

f = lambda x, s=0, n=0: f(x, s+n*2+1, n+1) if s < x else n-1

print(f(100))

Arnauld

Posted 2017-04-07T03:20:33.900

Reputation: 111 334

1

This works (47 chars):

print(sum(map(lambda n:0==n**.5%1,range(100))))

n**.5 will return a float, which will be a whole number if n is a perfect square. We can then do %1 to get the fractional part, which will be 0 if n is a perfect square, so adding 0== will give us a boolean of whether or not n is a perfect square.

We can then make that into a lambda function and map that onto the range, which will give us a list of booleans, which can be summed to give us how many True values were there.

As in Ben Frankel's answer, it's actually shorter to use list comprehension than map. I didn't think of that. That gets us down to 41 chars.

print(sum(0==n**.5%1for n in range(100)))

EDIT: removed one byte by replacing not with 0==

nog642

Posted 2017-04-07T03:20:33.900

Reputation: 151

0

How about this?

print(sum(x==int(x**.5)**2for x in range(1,101)))

This is a sum of boolean values, so they are treated as 0 for False and 1 for True.

EDIT: As in Riker's answer, x**.5%1==0 is shorter than x==int(x**.5)**2.

Ben Frankel

Posted 2017-04-07T03:20:33.900

Reputation: 301