I saw a math question does the sum of 1/k for natural numbers k=1,inf converge?

My first thought was that they must, as 1/k approaches 0 pretty quickly. To test my assumption I turned to and was surprised by the result...

sum( [1/k for k in range(int(1E6), int(1E7)]) # ~2.3
sum( [1/k for k in range(int(1E7), int(1E8)]) # also ~2.3

Very much not what I expected!

I recently learned about list comprehension (above) and generator expressions in . I really like them. I figured that it would be about the same in the sum statement above, but a quick test shows that generator expression is the way to go so revise to below to use less memory...

sum( (1/k for k in range(int(1E6), int(1E7)) ) # ~2.3
sum( (1/k for k in range(int(1E7), int(1E8)) ) # also ~2.3

@cryptoxic I think.. if you keep from 1E6 -> 1E7, then 1E7 -> 1E8 then 1E8 -> 1E9 ..etc.. you will find that they converge on math.log(10)


@cryptoxic yeah, the list expression generates the entire list first and then sums it whereas the generator expression is roughly equivalent to

sum = 0
for k in range(int(1E8)):
sum += 1/k

i.e. only one value is generated at a time. Generally you always want a generator expression unless you need to explicitly interact with the entire list

@cryptoxic Generators are crazy pants cool! I'm still trying to warm up to list comprehensions. I understand them now, but they still feel kind of ... awkward to me. At least their syntax does.

@feoh I am on the other side of the fountain, I found the generator expressions to be more intuitive than a generator function! I can at least see how one syntax makes more sense than another.

If the generator is in parents already, one can even save the second pair of parents:
sum(1/k for k in range(int(1E6), int(1E7))

/me fires up htop and python and runs test... 🤯

Thanks for the tip, @kirschwipfel

Sign in to participate in the conversation

Just a general instance with a catchy name. We're running glitch-soc!