Alternative to Decimal type
mwilson at the-wire.com
Mon Jun 9 15:07:03 CEST 2008
Frank Millman wrote:
> Hi all
> I have a standard requirement for a 'decimal' type, to instantiate and
> manipulate numeric data that is stored in a database. I came up with a
> solution long before the introduction of the Decimal type, which has
> been working well for me. I know the 'scale' (number of decimal
> places) of the number in advance. When I read the number in from the
> database I scale it up to an integer. When I write it back I scale it
> down again. All arithmetic is done using integers, so I do not lose
> There is one inconvenience with this approach. For example, if I have
> a product quantity with a scale of 4, and a price with a scale of 2,
> and I want to multiply them to get a value with a scale of 2, I have
> to remember to scale the result down by 4. This is a minor chore, and
> errors are quickly picked up by testing, but it does make the code a
> bit messy, so it would be nice to find a solution.
> I am now doing some refactoring, and decided to take a look at the
> Decimal type. My initial impressions are that it is quite awkward to
> use, that I do not need its advanced features, and that it does not
> help solve the one problem I have mentioned above.
> I therefore spent a bit of time experimenting with a Number type that
> suits my particular requirements. I have come up with something that
> seems to work, which I show below.
> I have two questions.
> 1. Are there any obvious problems in what I have done?
> 2. Am I reinventing the wheel unnecessarily? i.e. can I do the
> equivalent quite easily using the Decimal type?
> from __future__ import division
> class Number(object):
> def __init__(self,value,scale):
> self.factor = 10.0**scale
> if isinstance(value,Number):
> value = value.value / value.factor
I think this could lead to trouble. One complaint against binary floating
point is that it messes up low-order decimal digits, and this ensures that
all calculations are effectively done in binary floating point. Better, I
think would be
if isinstance (value, Number):
self.value = value.value
self.scale = scale + value.scale
and be done with it. Of course, this means self.scale no longer gives the
preferred number of fractional digits. My bias: I did a DecimalFloat class
way back when, when Decimal was being discussed, and separated the exponent
for calculations from the rounding precision for display.
More information about the Python-list