围绕Python的数字列表并保持其总和

use*_*024 8 python numpy sum rounding

我在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
Run Code Online (Sandbox Code Playgroud)

我需要一种有效的方法来修改我的新圆形数组,使得总和也是187976.61.2便士差异需要应用于项目7和6,因为它们在舍入条目和原始条目之间具有最大差异.

Acu*_*nus 10

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

>>> from iteround import saferound
>>> saferound([1.0, 2.1, 3.6], places=0)
[1.0, 2.0, 4.0]
Run Code Online (Sandbox Code Playgroud)


Mar*_*som 5

第一步是计算所需结果与实际总和之间的误差:

>>> error = originalTotal - sum(myRoundedList)
>>> error
0.01999999996041879
Run Code Online (Sandbox Code Playgroud)

这可以是积极的,也可以是消极的.由于每个项目myRoundedList都在实际值的0.005以内,因此该错误将小于原始数组的每个项目的0.01.您可以简单地除以0.01并舍入以获得必须调整的项目数:

>>> n = int(round(error / 0.01))
>>> n
2
Run Code Online (Sandbox Code Playgroud)

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

>>> 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
Run Code Online (Sandbox Code Playgroud)


Jai*_*ime 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
Run Code Online (Sandbox Code Playgroud)