减去截断的数字:结果不被截断吗?

时间:2019-08-13 00:10:21

标签: python truncated

我正在尝试创建一个函数,该函数将根据指定的百分比(好的,预算)将数字分为几类。

我使用了分开的浮点数,从网络上获取了一个测试截断函数,并在第100位之后将所有内容都截断了。这是为了防止所有类别的总和大于初始数量。然后,我从初始金额中减去类别的总和,得出“余数”,在我的示例中应为0.03或3美分。

def budget_calc(amount):

    budget = {"t":0.10,
            "c":0.50,
            "s":0.20,
            "e":0.05,
            "c/m":0.05,
            "tr":0.05,
            "o":0.03,
            "g/d":0.02}

    def truncate(x, d):

        return int(x*(10.0**d))/(10.0**d)


    def multp(key):

        cate = truncate(amount * budget.get(key), 2)

        return cate


    new_amounts = {'t': multp('t'),
              'c': multp('c'),
              's': multp('s'),
              'e': multp('e'),
              'c/m': multp('c/m'),
              'tr': multp('tr'),
              'o': multp('o'),
              'g/d': multp('g/d')}

    remainder = amount - sum(new_amounts.values())
    new_amounts.update(remainder = remainder)

    return new_amounts

这就是我得到的:

budget_calc(148.72)

     {'t': 14.87,
     'c': 74.36,
     's': 29.74,
     'e': 7.43,
     'c/m': 7.43,
     'tr': 7.43,
     'o': 4.46,
     'g/d': 2.97,
     'remainder': 0.029999999999972715} #<-- this number should only contain two decimal points

那么,沿线某处的“截断”功能仅显示截断的数字,实际上并未消除多余的数字吗?那里的数学也是错误的148.72-所有截断数字的总和(148.69)应该为0.03。看起来就是这样,另外的诊断会很棒。

2 个答案:

答案 0 :(得分:1)

您从未将truncate应用于remainder计算,您只是将截断的数字相加并相减。 sum中的每一个加法都可能会产生一个小的精度问题,而减法会引入另一个精度问题,并且将结果截断会导致严重的问题(因为将值减小一点的错误会在您使用时导致巨大的错误)截短)。如果要始终对其进行四舍五入,则必须每次对其进行四舍五入。我还建议使用math.fsum来减少求和错误:

>>> d = {'t': 14.87,
         'c': 74.36,
         's': 29.74,
         'e': 7.43,
         'c/m': 7.43,
         'tr': 7.43,
         'o': 4.46,
         'g/d': 2.97}
>>> import math
>>> sum(d.values())        # Loses precision
148.69000000000003
>>> math.fsum(d.values())  # More accurate!
148.69
>>> 148.72 - sum(d.values())  # Already lost precision, so result wrong
0.029999999999972715
>>> 148.72 - math.fsum(d.values())  # Sadly, even with accurate fsum, final subtraction is "wrong"
0.030000000000001137
>>> round(148.72 - math.fsum(d.values()), 2)  # But we can always round it off
0.03

所有这些,尝试使用float执行此操作本质上容易出错; float精度以二进制表示,并且您需要十进制精度。如果需要十进制精度,我强烈建议您使用the decimal module,它具有一百万个旋钮,可以使其精确地表现 您想要的样子。

答案 1 :(得分:1)

这是由于浮点计算的不精确性,就像

0.1 + 0.2 = 0.30000000000000004

在javascript中。

您可以在Why does adding two decimals in Javascript produce a wrong result?

中找到有关此信息的更多信息

一种解决方案是舍入而不是截断,并且舍入您的提醒。