from decimal import getcontext, Inexact, Decimal def decimalsum(iterable, start=Decimal('0')): '''Exact sum of Decimal/int/float mix; Result is *unrounded*''' if not isinstance(start, Decimal): start = Decimal(start) # We need our own context and we can't just set it once because # the loop could be over a generator/iterator/coroutine ctx = getcontext().copy() ctx.traps[Inexact] = True one = Decimal(1) total = start for x in iterable: if not isinstance(x, Decimal): x = Decimal(x) # Increase the precision until we get an exact result. while True: try: total = total.fma(one, x, ctx) break except Inexact: ctx.prec *= 2 # Result is exact and unrounded. return total D = Decimal assert decimalsum([D("1.02"), 3e100, D("0.98"), -3e100]) == 2