12

我在 Python 中有一个十进制数的列表或数组。我需要将它们四舍五入到最接近的 2 位小数,因为这些是货币金额。但是,我需要保持总和,即四舍五入到小数点后 2 位的原始数组的总和必须等于数组的四舍五入元素的总和。

到目前为止,这是我的代码:

myOriginalList = [27226.94982, 193.0595233, 1764.3094, 12625.8607, 26714.67907, 18970.35388, 12725.41407, 23589.93271, 27948.40386, 23767.83261, 12449.81318]
originalTotal = round(sum(myOriginalList), 2)
# Answer = 187976.61

# Using numpy
myRoundedList = numpy.array(myOriginalList).round(2)
# New Array = [ 27226.95    193.06   1764.31  12625.86  26714.68  18970.35  12725.41 23589.93 27948.4   23767.83  12449.81]

newTotal = myRoundedList.sum()
# Answer = 187976.59

我需要一种有效的方法来修改我的新舍入数组,使总和也是 187976.61。需要将 2 便士的差异应用于第 7 项和第 6 项,因为它们在四舍五入的条目和原始条目之间的差异最大。

4

4 回答 4

6

第一步是计算期望结果和实际总和之间的误差:

>>> error = originalTotal - sum(myRoundedList)
>>> error
0.01999999996041879

这可以是正面的也可以是负面的。由于其中的每一项myRoundedList都在实际值的 0.005 范围内,因此该误差将小于原始数组的每项 0.01。您可以简单地除以 0.01 并四舍五入得到必须调整的项目数:

>>> n = int(round(error / 0.01))
>>> n
2

现在剩下的就是选择应该调整的项目。最佳结果来自于首先调整最接近边界的那些值。您可以通过按原始值和舍入值之间的差异进行排序来找到它们。

>>> myNewList = myRoundedList[:]
>>> for _,i in sorted(((myOriginalList[i] - myRoundedList[i], i) for i in range(len(myOriginalList))), reverse=n>0)[:abs(n)]:
    myNewList[i] += math.copysign(0.01, n)

>>> myRoundedList
[27226.95, 193.06, 1764.31, 12625.86, 26714.68, 18970.35, 12725.41, 23589.93, 27948.4, 23767.83, 12449.81]
>>> myNewList
[27226.95, 193.06, 1764.31, 12625.86, 26714.68, 18970.359999999997, 12725.42, 23589.93, 27948.4, 23767.83, 12449.81]
>>> sum(myNewList)
187976.61
于 2013-04-05T04:53:01.190 回答
6

正如kettlehell 的回答中所指出的,请考虑PyPI 包iteround。但是,它内部并不使用 NumPy。

>>> from iteround import saferound
>>> saferound([1.0, 2.1, 3.6], places=0)
[1.0, 2.0, 4.0]
于 2018-10-14T21:53:02.167 回答
1

关于使用浮点数的所有注意事项:

delta_pence = int(np.rint((originalTotal - np.sum(myRoundedList))*100))
if delta_pence > 0:
    idx = np.argsort(myOriginalList - myRoundedList)[-delta_pence:]
    myRoundedList[idx] += 0.01
elif delta_pence < 0:
    idx = np.argsort(myOriginalList - myRoundedList)[:delta_pence]
    myRoundedList[idx] -= 0.01

>>> myRoundedList.sum()
187976.60999999999
于 2013-04-02T17:34:41.370 回答
1

首先,您不应该使用浮点数来存储资金(改用小数)。但下面我提供了一些非常通用的解决方案——您需要存储、累积和使用舍入差异的总和。一些冗长的(而不是非常pythonic ;-) 的示例与您的数字:

# define your accuracy
decimal_positions = 2

numbers = [27226.94982, 193.0595233, 1764.3094, 12625.8607, 26714.67907, 18970.35388, 12725.41407, 23589.93271, 27948.40386, 23767.83261, 12449.81318]
print round(sum(numbers),decimal_positions)
>>> 187976.61

new_numbers = list()
rest = 0.0
for n in numbers:
    new_n = round(n + rest,decimal_positions)
    rest += n - new_n
    new_numbers.append( new_n )

print sum(new_numbers)
>>> 187976.61
于 2013-04-02T17:48:53.647 回答