【问题标题】:Subtracting Truncated Numbers: Result isn't truncated? [duplicate]减去截断的数字:结果没有被截断? [复制]
【发布时间】:2019-12-19 12:46:42
【问题描述】:

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

我采用了分开的浮点数,从网上抓取了一个测试截断函数,并截断了百位之后的所有内容。这是为了防止所有类别的总和大于初始数量。然后我从初始金额中减去类别的总和,得到“余数”,在我的示例中应该是 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。看起来就是这样,额外的诊断会很棒。

【问题讨论】:

标签: python truncated


【解决方案1】:

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

0.1 + 0.2 = 0.30000000000000004

在 JavaScript 中。

你可以在这里找到更多信息Why does adding two decimals in Javascript produce a wrong result?

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

【讨论】:

    【解决方案2】:

    您从未将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
    

    话虽如此,尝试使用floats 执行此操作本质上很容易出错; float 精度以二进制表示,您需要十进制精度。如果您需要小数精度,我强烈建议您使用the decimal module,它有一百万个旋钮,可以完全按照您想要的方式运行。

    【讨论】:

      猜你喜欢
      • 2014-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-20
      • 2015-11-11
      • 1970-01-01
      • 2010-11-03
      相关资源
      最近更新 更多