As I tried to explain in comments, the problem is that you're using floating point numbers.
For more information on floating point, see 1, 2.
The issue is that 277.9
is not actually stored as 277.9
, but rather something "very close":
print('%.40f' % a)
277.8999999999999772626324556767940521240234
The solution isn't to use some arbitrary heuristic to tell whether the math is slightly off and try to correct for it. We know the math is slightly off -- that's the gift and curse given to us by floating point.
The real solution is to use fixed point math, for example, with Python's decimal
module.
Edit
from decimal import Decimal
values = [
('tens', Decimal(10)),
('fives', Decimal(5)),
('ones', Decimal(1)),
('tenths', Decimal('0.1'))
]
def get_digits(num):
output_dict = {}
for place, value in values:
output_dict[place] = int(num // value) # Cast from Decimal to int
num = num % value
return output_dict
num = Decimal('277.9')
print(get_digits(num))
# {'tens': 27, 'ones': 2, 'tenths': 9, 'fives': 1}
num = Decimal('277.6')
print(get_digits(num))
#{'tens': 27, 'ones': 2, 'tenths': 6, 'fives': 1}
The above code is very similar to yours, but uses Python's decimal module. No heuristic check is needed. The code just works, because decimals are represented accurately.