将 Python 数字列表四舍五入并保持它们的总和
问题描述
我在 Python 中有一个十进制数的列表或数组.我需要将它们四舍五入到最接近的 2 位小数,因为这些是货币金额.但是,我需要保持总和,即四舍五入到小数点后 2 位的原始数组的总和必须等于数组的四舍五入元素的总和.
I have a list or an array of decimal numbers in Python. I need to round them to the nearest 2 decimal places as these are monetary amounts. But, I need the overall sum to be maintained, i.e. the sum of the original array rounded to 2 decimal places must be equal to the sum of the rounded elements of the array.
到目前为止,这是我的代码:
Here's my code so far:
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 项,因为它们在四舍五入的条目和原始条目之间的差异最大.
I need an efficient way of amending my new rounded array such that the sum is also 187976.61. The 2 pence difference needs to be applied to items 7 and 6 as these have the greatest difference between the rounded entries and the original entries.
解决方案
第一步,计算期望结果与实际总和的误差:
The first step is to calculate the error between the desired result and the actual sum:
>>> error = originalTotal - sum(myRoundedList)
>>> error
0.01999999996041879
这可以是正面的也可以是负面的.由于 myRoundedList
中的每个项目都在实际值的 0.005 范围内,因此此错误将小于原始数组的每个项目的 0.01.您可以简单地除以 0.01 并四舍五入得到必须调整的项目数:
This can be either positive or negative. Since every item in myRoundedList
is within 0.005 of the actual value, this error will be less than 0.01 per item of the original array. You can simply divide by 0.01 and round to get the number of items that must be adjusted:
>>> n = int(round(error / 0.01))
>>> n
2
现在剩下的就是选择应该调整的项目.最佳结果来自于首先调整最接近边界的那些值.您可以通过按原始值和舍入值之间的差异进行排序来找到它们.
Now all that's left is to select the items that should be adjusted. The optimal results come from adjusting those values that were closest to the boundary in the first place. You can find those by sorting by the difference between the original value and the rounded value.
>>> 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
相关文章