# extend methods of decimal module

Wolfgang xpysol at gmail.com
Fri Feb 28 00:43:48 CET 2014

On Friday, February 28, 2014 12:00:45 AM UTC+1, Mark H. Harris wrote:
> On Thursday, February 27, 2014 10:24:23 AM UTC-6, Oscar Benjamin wrote:
> >>>> from decimal import Decimal as D
>
> > >>> D(0.1)
>
> > Decimal('0.1000000000000000055511151231257827021181583404541015625')
>
> >
> hi Oscar,  well,  that's not what I'm doing with my  D()...  I'm not just making D() mimic Decimal... look inside it...  there's a  str()  call....   consider the following experiment and you'll see what I'm talking about...
> >>> from dmath import *
> >>> pi = D(piagm(32))
> >>> pi
> Decimal('3.14159265358979323846264338327950')
> >>> pi * Decimal(.1)
> Decimal('0.31415926535897934128560682837111')
> >>>
> >>> pi * D(.1)
> Decimal('0.31415926535897932384626433832795')
> >>>
> >>>
> You will notice that   Decimal(.1)  and  my  D(.1)  work against  PI  differently... in fact, Decimal(.1) decimates PI....   <sorry for the PUN>
> The reason is that Decimal(.1) stores the erroneous float in the Decimal object including the float error for  .1    and   D(.1)  works correctly  because the D(.1) function in my dmath.py first converts the .1 to a string value before handing it to Decimal's constructor(s)

What Oscar tried to make clear is that Decimal(.1) does not store an "erroneous" float in the Decimal object, but an "honest" one.
Maybe this becomes clearer with calculations instead of literal values:

>>> 1000000000000000055511151231257827021181583404541015625/10**55
0.1

now try:
D(1000000000000000055511151231257827021181583404541015625/10**55)
vs
Decimal(1000000000000000055511151231257827021181583404541015625/10**55)
for an example that it is not better, in general, to go through the str()-mediated rounding you are doing.

Of course, if the user *intended* that float(.1) to mean exactly 0.1 then your D class does a good job at guessing, but only then.
The Decimal class, on the other hand, leaves the choice to the user as you are illustrating perfectly in your own example below:

> Now, try this experiment:    again from IDLE and dmath.py
>
> >>> from dmath import *
> >>> pi = D(piagm(32))
> >>> pi
> Decimal('3.14159265358979323846264338327950')
> >>>
> >>> pi * Decimal(str(.1))
> Decimal('0.31415926535897932384626433832795')
> >>>
> >>> pi * D(.1)
> Decimal('0.31415926535897932384626433832795')

see? Decimal(.1) gives the exact representation of the float, but Decimal('.1') is the way to get your D()'s default behavior.

> You see?   All of my functions make certain that when the Decimal objects are created that the string constructor gets called....   so that, in this case,   .1  really is  0.1   precisely, not floating format.

Yes, just that this is almost never what your users will want to happen ...
The Decimal constructor is really well designed, so stick to it !

Best,
Wolfgang