Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am working with currencies, and so have been using the decimal module to rule out any floating point weirdness in the following maths.

I have to add together a number of decimal amounts, find an average of them, add ten percent, and then round it to the nearest round £. I then need to do more decimal maths with the output, so it'll need to be a decimal (or an integer) so I can play with it. Adding the decimals has been fairly straightforward, but doing the rest of the maths has left me with this line:

result = decimal.Decimal(round((sum_of_items / count_of_items) * decimal.Decimal(1.1), 0))

It strikes me that this isn't particularly elegant, as I'm converting the decimal average+10% to a float just to round it off, and then turning the result back into a decimal.

Am I risking any floating point weirdness with that brief conversion back to floating point? And is there any way to achieve the same effect as round using the decimal module so I don't have to go decimal->float->decimal?

share|improve this question
1  
Don't use decimal.Decimal(1.1). Always initialize decimal constants with strings, to avoid rounding error: decimal.Decimal('1.1') –  user2357112 May 8 at 22:00
add comment

2 Answers 2

up vote 4 down vote accepted

I was actually unaware of the decimal module -- I've +1 your question just for that.

Taking a quick look at the docs, Decimal is specifically designed to avoid artifacts of binary floats and work like "people" math. Because of that I would be suspicious of the conversion to float, no matter how brief. Can you use the quantize() function instead of round()? The quantize method "rounds a number to a fixed exponent. This method is useful for monetary applications that often round results to a fixed number of places" and sounds well suited to your application.

share|improve this answer
add comment

I thin you should rely more on the Decimal object to do the right thing; rather than rounding, set your precision with, for instance: getcontext().prec=6 and then just do Decimal(sum_of_items) / Decimal(count_of_items) * Decimal(1.1)

Alternately, just do all your multiplies before you do your divides, to keep the most precision.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.