Потеря точности при добавлении больших натуральных чисел (с экспоненциальными обозначениями) и небольших натуральных чисел в python 3

    n = int(input())
    sum1 = (n * (n + 1)) / 2
    sum2 = int(sum1)
    sum2 = sum2 + 100
    sum1 = sum1 + 100
    if sum2 == sum:
        print("same")
    elif sum2 > sum1:
        print("less")
    elif sum2 < sum1:
        print("more")
    print("sum1=",sum1)
    print("sum2=",sum2)

ВВОД:n=10000000000(или больше 10^9)
ВЫВОД: меньше
sum1= 5.0000000005e+19
sum2= 50000000005000003684

И sum1, и sum2 должны быть равны, но почему-то я теряю точность, когда в игру вступают экспоненты, и если я попытаюсь напечатать разницу между sum1 и sum2, я получу ноль (0,0) в качестве вывода. Для меньших значений n я получаю точные ответы.

Итак, как мне избежать потери точности и получить точные результаты, когда я добавляю действительно большие целые числа и меньшие интегралы?
Примечание. Этот код является лишь частью более крупной программы, поэтому, пожалуйста, держите свои ответы в общем виде. Спасибо.


person James Bansal    schedule 10.09.2020    source источник
comment
Да, это неотъемлемое ограничение чисел с плавающей запятой. Вы никогда не сможете получить точные результаты, используя числа с плавающей запятой.   -  person juanpa.arrivillaga    schedule 10.09.2020
comment
Держите все как целые числа, и все будет в порядке - в Python они имеют произвольную точность. Если n является целым числом, то n * (n+1) должно делиться на 2, поэтому вместо n * (n+1) / 2 используйте целочисленное деление, то есть n * (n+1) // 2, и вы получите целое число со значением, которое значение с плавающей запятой имело бы, если бы оно имело достаточная точность. Проблема, с которой вы сталкиваетесь, заключается в не добавлении больших и меньших целых чисел, как утверждается в вопросе, а в добавлении поплавков после того, как вы создали их с помощью оператора деления /.   -  person alani    schedule 10.09.2020
comment
Дополнительные сведения о проблемах с типами float см. в разделе Не работает ли математика с плавающей запятой?   -  person Mark Ransom    schedule 10.09.2020


Ответы (1)


Как указывает Алани, в sum1 = (n * (n + 1)) / 2 есть неявное преобразование в float. Например. isinstance(1/1, float) == True. Используйте целочисленное деление //. n*(n+1) всегда четное, поэтому у вас никогда не будет результата N.5, при котором вы потеряете точность. Кроме того, repr из floats всегда имеет либо десятичную точку (1.0), либо показатель степени (1e+20), либо и то, и другое, поэтому, если вы когда-нибудь увидите это, знайте, что у вас есть числа с плавающей запятой.

person jpkotta    schedule 10.09.2020
comment
Не только repr, но и str, что и будет использовать print. - person Mark Ransom; 10.09.2020