Round a list of numbers in Python and save the sum

I have a list or 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 total amount that needs to be saved, 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 is my code:

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

I need an efficient way to modify my new rounded array, so the sum is also equal to 187976.61. The difference of 2 pence should apply to paragraphs 7 and 6, since they have the largest difference between rounded records and the original records.

Any ideas?

+5
source share
4 answers

- :

>>> 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
+4

:

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
+1

, float ( Decimals). - , . ( 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
+1

, , O (n * log (n)) ( n). , ( ) , ( min/max, ).

python, ( ( )).

import math
import heapq

def roundtosum(l, r):
    q = 10**(-r)
    d = int((round(sum(l),r) - sum([ round(x, r) for x in l ])) * (10**r))
    if d == 0:
        return l
    elif d in [ -1, 1 ]:
        c, _ = max(enumerate(l), key=lambda x: math.copysign(1,d) * math.fmod(x[1] - 0.5*q, q))
        return [ round(x, r) + q * math.copysign(1,d) if i == c else round(x, r) for (i, x) in enumerate(l) ]
    else:
        c = [ i for i, _ in heapq.nlargest(abs(d), enumerate(l), key=lambda x: math.copysign(1,d) * math.fmod(x[1] - 0.5*q, q)) ]
        return [ round(x, r) + q * math.copysign(1,d) if i in c else round(x, r) for (i, x) in enumerate(l) ]

d - , , . d , . d 1 -1, min max. heapq.nlargest D=abs(d) .

, max, nlargest ?! min max , .

, O (n + D * log (n)).

Note. With a bunch, you can create an O (n + D ^ 2 * log (D)) algorithm, since the top elements dshould be at the top levels of the D heap, and you can arrange this list in steps O (D ^ 2 * log (D) ) If nhuge, but dvery small, it can mean a lot.

(The right to re-review is reserved (because it is after midnight).

0
source

All Articles