Alternative to Decimal type

Mel 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
> accuracy.
> 
> 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.

        Cheers,         Mel




More information about the Python-list mailing list