Это одна из тонких точек арифметики IEEE-754 c. Когда вы пишете:
>>> 1/3
0.3333333333333333
напечатанное число является «округленной» версией числа, которое внутренне сохраняется как результат 1/3
. Это именно то, что было решено показать конвертацией Double -> String в процессе печати. Но вы уже знали это.
Теперь вы можете спросить, есть ли способ узнать, в чем разница? Да, используйте модуль fractions
:
>>> from fractions import Fraction
>>> Fraction(1, 3) - Fraction(1/3)
Fraction(1, 54043195528445952)
Ах, это интересно. Таким образом, оно немного меньше фактического значения, а разница составляет 1 / 54043195528445952
. Это, конечно, ожидаемо.
Итак, что происходит, когда вы «складываете» два из них вместе. Давайте посмотрим:
>>> Fraction(2,3) - Fraction(1/3+1/3)
Fraction(1, 27021597764222976)
Опять же, вы близки к 2/3
rds, но все еще не совсем там. Давайте сделаем сложение еще раз:
>>> Fraction(1,1) - Fraction(1/3+1/3+1/3)
Fraction(0, 1)
Бин go! с 3 из них представление точно 1
.
Почему это? Ну, в каждом добавлении вы получаете число, близкое к тому, что, по вашему мнению, должно быть ответом, но внутреннее округление приводит к тому, что результат становится близким числом, которое вы не имели в виду. С тремя дополнениями, что говорит вам ваша интуиция и что совпадает внутреннее округление.
Важно подчеркнуть, что сложение 1/3 + 1/3 + 1/3
не делает , а не дает 1
; он просто создает внутреннее значение, ближайшее представление которого в виде значения с плавающей точкой двойной точности IEEE-754 равно 1
. Это тонкое, но важное отличие. Надеюсь, это поможет!