Precision of decimals in Python

纵饮孤独 提交于 2019-12-02 21:56:32

问题


I don't mean precision as in how many numbers are displayed after the decimal. I mean precision as in the decimal I am trying to use in this pictograph function keeps coming up one tenth shy of what it should be. I have tried using multiple different strategies including importing the decimal module. Here is the function I am trying to use.

values = [('tens', 10), ('fives', 5), ('ones', 1), ('tenths', 0.1)]

def get_digits(num):
    num = int(num * 10)
    num = float(num) / 10

    output_dict = {}
    for place, value in values:
        output_dict[place] = int(num // value)
        num = num % value

    return output_dict

using get_digits(277.9), yields {'tens': 27, 'ones': 2, 'tenths': 8, 'fives': 1}

I need for it to say {'tens': 27, 'ones': 2, 'tenths': 9, 'fives': 1}

Fixing it by adding 1 to the tenths after the dictionary is populated does not work, because not every decimal comes out imprecisely.

get_digits(277.6) returns {'fives': 1, 'tenths': 6, 'tens': 27, 'ones': 2}

I've been scouring the forums for an answer, but nothing quite gets it. Any assistance would be greatly appreciated.


回答1:


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.



来源:https://stackoverflow.com/questions/21210727/precision-of-decimals-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!