Вообще-то описанную проблему можно проиллюстрировать проще:
>>> 0.5+2.7, 0.4+2.8
(3.2, 3.1999999999999997)
Это нормальная ситуация для чисел с плавающей точкой. Она связана с тем, что для любой системы счисления (двоичной, десятичной, троичной) есть числа, которые нельзя записать в виде конечной последовательности n-ричных разрядов. Например, в десятичной системе число 1/3 будет выглядеть как бесконечная последовательность троек после запятой. Если мы остановимся, то получим не 1/3 а что-то поменьше. Зато в троичной системе это число замечательно представляется как 0.1. Одна девятая в троичной системе равна 0.01.
Та же проблема, например, у десятичного числа 0.2 при переводе в двоичную систему:
2/10==1/5==1/8+1/16+1/128+1/256+1/2048+1/4096+(...)==0,00110011(0011)[в двоичной системе]
Как видим это периодическое число и двоичные разряды "0011" повторяются в нём после запятой бесконечно.
Компьютерное представление чисел с плавающей точкой подразумевает их хранение в конечном количестве двоичных разрядов. Это значит, что многие вполне нормально записываемые в десятичной форме дробные числа просто не могут абсолютно точно храниться в компьютере (если речь идёт о floatpoint).
Имеенно поэтому программистов учат на первом курсе института никогда не сравнивать числа с плавающей точкой на строгие равенство и неравенство. С учетом погрешности из-за округления двоичных разрядов это просто бессмысленно и некорректно.
Зато, вместо сравнения на равенство, можно сравнивать
abs(a-b)<eps
, где
a
и
b
-- числа в формате с плавающей точкой, а eps -- это некоторая пренебрежительно малая величина. Вообще-то, думаю, можно вычислить даже минимальное значение этой величины, чтобы она покрыла все неприятности с округлением двоичных разрядов.