我正在尝试创建一个函数,该函数将根据指定的百分比(好的,预算)将数字分为几类。
我使用了分开的浮点数,从网络上获取了一个测试截断函数,并在第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。看起来就是这样,另外的诊断会很棒。
答案 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?
中找到有关此信息的更多信息一种解决方案是舍入而不是截断,并且舍入您的提醒。