Как улучшить код по суммированию натуральных чисел?

Задача: Дано целое положительное число N. Выведите максимально возможную сумму последовательных целых чисел от 1 до n так, чтобы эта сумма была строго меньше заданного значения N. Мой код:

n = int(input())
def get_num(n):

    sum = 0
    for i in range(1, n + 1):
        sum += i
        if sum >= n:
            print(sum - i)
            break
    return sum
get_num(n)

Как можно улучшить? Задача решена конечно, но криво. Не могу понять как правильно прописать момент с суммой, где она меньше числа n. Если убрать print(sum - i), то вывод уже идет некорректный.


Ответы (2 шт):

Автор решения: MBo

Например, исправить можно так:

def get_num(n):
    summ = 0
    i = 1
    while summ + i < n:
        summ += i
        i +=1
    return summ

А по уму вместо перебора нужно использовать формулу суммы арифметической прогрессии и решить квадратное неравенство

import math
def get_num2(n):
    x = math.ceil((math.sqrt(1 + 8 * n) - 1)/2) - 1
    return x*(x+1)//2
→ Ссылка
Автор решения: Stanislav Volodarskiy

Если приводить в порядок ваш код, то надо поправить сумму перед возвращением:

def get_num(n):
    s = 0
    for i in range(1, n + 1):
        s += i
        if s >= n:
            s -= i
            break
    return s


print(get_num(int(input())))

for в решении смотрится странно. Без него будет проще:

def get_num(n):
    t = 0  # next term in sum
    s = 0  # current sum
    while s < n:
        t += 1
        s += t
    return s - t  # correct last term

Последовательное сложение не наш способ. Решим задачу аналитически.

i=1ni < N исходное неравенство
i=1ni ≤ N - 1 замена неравенства на нестрогое
n(n + 1)/2 ≤ N - 1 сумма арифметической прогрессии
4n(n + 1) ≤ 8N - 8
4n2 + 4n + 1 - 1 ≤ 8N - 8
(2n + 1)2 ≤ 8N - 7
2n + 1 ≤ √(8N - 7)
2n + 1 ≤ ⌊√(8N - 7)⌋ левая часть целая, берём из правой целую часть
n ≤ (⌊√(8N - 7)⌋ - 1) / 2
n ≤ ⌊(⌊√(8N - 7)⌋ - 1) / 2⌋ левая часть целая, берём из правой целую часть

Целую часть корня ⌊√⌋ извлекает math.isqrt. Деление в конце ⌊... / 2⌋ целочисленное - //.

Можно считать:

def get_num(n):
    m = (math.isqrt(8 * n - 7) - 1) // 2
    return m * (m + 1) // 2
→ Ссылка