> num = 0
total = 0
while(True):
num = 1
total = num
if total < 100:
break
print('The last number is %d and total is %d' % (num, total))
The answer is supposed to be "The last number is 13 and total is 91" but I keep getting 1 for the answers. I know there's something wrong with the sixth line but I can't figure out how to make it right.
CodePudding user response:
Even with the fix of if total >= 100: break
you'll always get one higher number (and total) than the limit. That's because total
is first assigned and then checked. So it's assigned 105
with number being 14
and then checked to see if it exceeds 100
.
Two changes:
- check what
total
would be before assigning it. - check this potential value of total at the start of the loop
num = 0
total = 0
while True:
if total num 1 > 100:
break
num = 1
total = num
print(f'The last number is {num} and total is {total}')
# The last number is 13 and total is 91
And using an Assignment Expression (aka Walrus operator) you can reduce the re-calculation by assigning checked value to the next possible total:
num = 0
total = 0
while True:
if (next_total := total num 1) > 100:
break
num = 1
total = next_total # don't add, just assign
print(num, total) # the values are more important than printing
# 13 91
Edit: More advanced ways to do it using functional programming:
from itertools import accumulate, count, takewhile
result = list(takewhile(lambda t: t < 100, accumulate(count(1))))
print(result) # output for sanity
# [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91]
print(len(result), result[-1]) # num and total
# 13 91
or
from itertools import accumulate, count, takewhile
result = list(enumerate(takewhile(lambda t: t < 100, accumulate(count(1))), start=1))
print(result) # output for sanity
# [(1, 1), (2, 3), (3, 6), (4, 10), (5, 15), (6, 21), (7, 28), (8, 36), (9, 45), (10, 55), (11, 66), (12, 78), (13, 91)]
print(result[-1]) # each element is tuple of num and total
# (13, 91)
This second functional option appears longer, so why use it? It can be combined with a deque
of size 1 so that the result
list never needs to be stored, only calculated. And when the list isn't stored, we wouldn't know it's length len()
. So that index comes from enumerate(..., start=1)
. Without needing to store the list, it can be used for huge numbers without running out of RAM.
from collections import deque
from itertools import accumulate, count, takewhile
# items below is an iterable, not the actual list
items = enumerate(takewhile(lambda t: t < 100, accumulate(count(1))), start=1)
print(items)
# <enumerate object at 0x0000024F9CCBB5C0>
dd = deque(items, maxlen=1)
last_element = dd.pop()
print(last_element) # tuple of num & total
# (13, 91)
And with a huge limit:
def largest_until_total(limit):
items = enumerate(takewhile(lambda t: t < limit, accumulate(count(1))), start=1)
return deque(items, maxlen=1).pop()
print(largest_until_total(1_000_000_000_000)) # 1 trillion
# (1414213, 999999911791)
print(largest_until_total(1_000_000_000_000_000)) # 1 quadrillion
# (44721359, 999999997764120)
However, if you really wanted to use this for very large limits, it would be better to reverse engineer it with the "sum of first N natural numbers" formula N * (N 1) / 2
CodePudding user response:
Comments should be description enough.
def max_sum(m):
t, n = 0, 2
while True:
#linear sum
t_ = int((n 1)*(n/2))
#adjust num based on current condition
n = (t_<m)
n -= (t_>m)
#store or print respectively
if t_<m: t = t_
else:
print(f'num is {n} total is {t}')
break
max_sum(100)