How do you preserve precision when scaling a Decimal?
<p>How can you scale a <a href="https://docs.python.org/library/decimal.html#decimal.Decimal" rel="nofollow"><code>Decimal</code></a>, but keep its original precision? E.g.,</p>

<pre><code>&gt;&gt;&gt; from decimal import Decimal
&gt;&gt;&gt; Decimal('0.1230')
Decimal('0.1230') # Precision is 4.
</code></pre>

<p>Multiplication does not preserve the original precision:</p>

<pre><code>&gt;&gt;&gt; Decimal('0.1230') * 100
Decimal('12.3000') #  Precision is 6.
&gt;&gt;&gt; Decimal('0.1230') * Decimal('100')
Decimal('12.3000') # Precision is 6.
</code></pre>

<p>The <a href="https://docs.python.org/library/decimal.html#decimal.Decimal.shift" rel="nofollow"><code>.shift()</code></a> method only keeps the same number of decimal places when shifting by a negative amount:</p>

<pre><code>&gt;&gt;&gt; Decimal('0.1230').shift(2)
Decimal('12.3000') # Precision is 6.
&gt;&gt;&gt; Decimal('0.1230').shift(-2)
Decimal('0.0012') # Precision is 2.
</code></pre>

<p>Use <a href="https://docs.python.org/2/library/decimal.html#decimal.setcontext" rel="nofollow">setcontext</a>:</p>

<pre><code>&gt;&gt;&gt; mycontext=decimal.Context(prec=4)
&gt;&gt;&gt; decimal.setcontext(mycontext)
&gt;&gt;&gt; decimal.Decimal('0.1230')*decimal.Decimal('100')
Decimal('12.30')
</code></pre>

<p>If you want something that feels more local, use <a href="https://docs.python.org/2/library/decimal.html#decimal.localcontext" rel="nofollow">localcontext</a> and a context:</p>

<pre><code>import decimal as dec

with dec.localcontext() as ctx:
    ctx.prec=4
    d1=dec.Decimal('0.1230')*100

d2=dec.Decimal('0.1230')*100

&gt;&gt;&gt; d1, d2
12.30 12.3000
</code></pre>

<p>If you want something where the lesser precision representation (with no decimal integers use a default) you can do something like:</p>

<pre><code>def muld(s1, s2, dprec=40):
    with dec.localcontext() as ctx:
        d1=dec.Decimal(s1)
        d2=dec.Decimal(s2)
        p1=dprec if '.' not in s1 else len(d1.as_tuple().digits)
        p2=dprec if '.' not in s2 else len(d2.as_tuple().digits)
        ctx.prec=min(p1, p2)
        return d1*d2

&gt;&gt;&gt; muld('0.1230', '100')
12.30
&gt;&gt;&gt; muld('0.1230', '1.0')   
0.12
</code></pre>

python python-2.7