Detailed Explanation of decimal Type Conversion Example in python

  • 2021-07-01 08:00:17
  • OfStack

[Python Standard Library] decimal--Mathematical Operation of Fixed Point Number and Floating Point Number

Function: Decimal operation using fixed-point numbers and floating-point numbers.
Python version: 2.4 and later

The decimal module implements fixed-point and floating-point arithmetic operators, using a model that most people are familiar with, rather than a model that programmers are familiar with, that is, IEEE floating-point arithmetic operations implemented by most computer hardware. An Decimal instance can accurately represent any number, round it up or down, and limit the number of significant numbers.

Decimal

Decimal values are represented as instances of the Decimal class. The constructor takes 1 integer or string as an argument. Before creating an Decimal using a floating-point number, you can convert the floating-point number to a string, allowing the caller to explicitly handle the number of bits of the value, which cannot be accurately expressed if you use a hardware floating-point representation. In addition, using class methods from_float() Can be converted to an exact decimal representation.


import decimal 
fmt = '{0:<25} {1:<25}' 
print fmt.format('Input', 'Output') 
print fmt.format('-' * 25, '-' * 25) 
# Integer 
print fmt.format(5, decimal.Decimal(5)) 
# String 
print fmt.format('3.14', decimal.Decimal('3.14')) 
# Float 
f = 0.1 
print fmt.format(repr(f), decimal.Decimal(str(f))) 
print fmt.format('%.23g' % f, str(decimal.Decimal.from_float(f))[:25]) 

The floating-point value of 0.1 is not represented as an exact binary value, so the representation of float is different from that of Decimal. It is truncated to 25 characters in this output.

Decimal can also be created from tuples containing a symbolic flag (0 for positive and 1 for negative), the number tuple, and an integer exponent.


import decimal 
# Tuple 
t = (1, (1, 1), -2) 
print 'Input :', t 
print 'Decimal:', decimal.Decimal(t) 

Tuple-based representations are inconvenient to create, but they provide a portable way to derive decimal values without losing precision. The tuple form can be transmitted over the network, or stored in a database that does not support exact fractional values, and then reverted back to the Decimal instance.

Arithmetic operation

Decimal overloads simple arithmetic operators, so you can handle Decimal instances in the same way as built-in numeric types.


import decimal 
a = decimal.Decimal('5.1') 
b = decimal.Decimal('3.14') 
c = 4 
d = 3.14 
print 'a  =', repr(a) 
print 'b  =', repr(b) 
print 'c  =', repr(c) 
print 'd  =', repr(d) 
print 
print 'a + b =', a + b 
print 'a - b =', a - b 
print 'a * b =', a * b 
print 'a / b =', a / b 
print 
print 'a + c =', a + c 
print 'a - c =', a - c 
print 'a * c =', a * c 
print 'a / c =', a / c 
print 
print 'a + d =', 
try: 
 print a + d 
except TypeError, e: 
 print e 

The Decimal operator also accepts integer parameters, but floating-point values must be converted to Decimal instances.

In addition to basic arithmetic operations, Decimal also includes a number of methods to find logarithms based on 10 and natural logarithms. The values returned by log10 () and ln () are both Decimal instances, so they can be used directly in formulas like other values 1.

Special value

In addition to the expected numeric value, Decimal can represent many special values, including positive and negative infinities, "not a number" (NaN), and 0.


import decimal 
for value in [ 'Infinity', 'NaN', '0' ]: 
 print decimal.Decimal(value), decimal.Decimal('-' + value) 
print 
# Math with infinity 
print 'Infinity + 1:', (decimal.Decimal('Infinity') + 1) 
print '-Infinity + 1:', (decimal.Decimal('-Infinity') + 1) 
# Print comparing NaN 
print decimal.Decimal('NaN') == decimal.Decimal('Infinity') 
print decimal.Decimal('NaN') != decimal.Decimal(1) 

Adding to an infinity value returns another infinity value. Equality compared to NaN always returns false, while inequality always returns true. Comparing the size to NaN to determine the sort order is not clearly defined, which results in 1 error.

Context

So far, the previous examples have used the default behavior of decimal module. You can also use a context (context) to override certain settings, such as holding precision, how to complete rounding, error handling, and so on. The context can be applied to all Decimal instances in a single thread or locally to a small area of code.

1. Current context

To get the current global context, you can use getcontext ().


import decimal 
import pprint 
context = decimal.getcontext() 
print 'Emax   =', context.Emax 
print 'Emin   =', context.Emin 
print 'capitals =', context.capitals 
print 'prec   =', context.prec 
print 'rounding =', context.rounding 
print 'flags  =' 
pprint.pprint(context.flags) 
print 'traps  =' 
pprint.pprint(context.traps) 

This sample script shows the public properties of Context.

2. Precision

The prec attribute of the context controls the precision of new values created as a result of arithmetic operations. Literal values maintain accuracy according to this property.


import decimal 
d = decimal.Decimal('0.123456') 
for i in range(4): 
  decimal.getcontext().prec = i 
  print i, ':', d, d * 1 

To change the precision, you can directly assign a new value to this property.

3. Rounding

There are many options for rounding to ensure that the value is within the required accuracy range.

• ES 105EN_ES 106EN always tends to round up infinity.
• ES 108EN_ES 109EN always tends to round to 0.
ES 111EN_ES 112EN always tends to negative infinity and rounds down.
• ES 114EN_ES 115EN_ES 116EN If the last significant number is greater than or equal to 5, it is rounded in the opposite direction of 0; Otherwise, round towards 0.
• ES 118EN_ES 119EN_ES 120EN is similar to ES 121EN_ES 122EN_ES 123EN, except that if the last significant digit value is 5, the first 1 bit is checked. Even values cause the result to be rounded down, and odd values cause the result to be rounded up.
• ES 125EN_ES 126EN_ES 127EN is similar to ES 128EN_ES 129EN_ES 130EN, except that if the last significant digit is 5, the value is rounded in the opposite direction of 0.
• ES 132EN_ES 133EN is rounded in the opposite direction of 0.
• ES 135EN_05ES 136EN If the last 1 bit is 0 or 5, round in the opposite direction of 0; Otherwise rounded to 0.


import decimal 
 context = decimal.getcontext() 
ROUNDING_MODES = [ 
  'ROUND_CEILING', 
  'ROUND_DOWN', 
  'ROUND_FLOOR', 
  'ROUND_HALF_DOWN', 
  'ROUND_HALF_EVEN', 
  'ROUND_HALF_UP', 
  'ROUND_UP', 
  'ROUND_05UP', 
  ] 
header_fmt = '{:10} ' + ' '.join(['{:^8}'] * 6) 
print header_fmt.format(' ', 
            '1/8 (1)', '-1/8 (1)', 
            '1/8 (2)', '-1/8 (2)', 
            '1/8 (3)', '-1/8 (3)', 
            ) 
for rounding_mode in ROUNDING_MODES: 
  print '{0:10}'.format(rounding_mode.partition('_')[-1]), 
  for precision in [ 1, 2, 3 ]: 
    context.prec = precision 
    context.rounding = getattr(decimal, rounding_mode) 
    value = decimal.Decimal(1) / decimal.Decimal(8) 
    print '{0:^8}'.format(value), 
    value = decimal.Decimal(-1) / decimal.Decimal(8) 
    print '{0:^8}'.format(value), 
  print 

This program shows the effect of using different algorithms to round the same value to different precision.

4. Local context

When using Python 2.5 or later, you can use the with statement to apply a context to a block of code.


import decimal 
with decimal.localcontext() as c: 
  c.prec = 2 
  print 'Local precision:', c.prec 
  print '3.14 / 3 =', (decimal.Decimal('3.14') / 3) 
print 
print 'Default precision:', decimal.getcontext().prec 
print '3.14 / 3 =', (decimal.Decimal('3.14') / 3) 

Context supports the context manager API used by with, so this setting applies only within a block.

5. Context of each instance

The context can also be used to construct an Decimal instance, from which you can then inherit the precision and rounding parameters of the transformation.


import decimal 
# Set up a context with limited precision 
c = decimal.getcontext().copy() 
c.prec = 3 
# Create our constant 
pi = c.create_decimal('3.1415') 
# The constant value is rounded off 
print 'PI  :', pi 
 
# The result of using the constant uses the global context 
print 'RESULT:', decimal.Decimal('2.01') * pi 

In this way, the application can be distinguished from the user data accuracy and choose the constant value accuracy additionally.

6. Threads

The "global" context is actually a thread-local context, so it is entirely possible to configure individual threads with different values.


import decimal 
import threading 
from Queue import PriorityQueue 
class Multiplier(threading.Thread): 
  def __init__(self, a, b, prec, q): 
    self.a = a 
    self.b = b 
    self.prec = prec 
    self.q = q 
    threading.Thread.__init__(self) 
  def run(self): 
    c = decimal.getcontext().copy() 
    c.prec = self.prec 
 decimal.setcontext(c) 
    self.q.put( (self.prec, a * b) ) 
    return 
 a = decimal.Decimal('3.14') 
b = decimal.Decimal('1.234') 
# A PriorityQueue will return values sorted by precision, no matter 
# what order the threads finish. 
q = PriorityQueue() 
threads = [ Multiplier(a, b, i, q) for i in range(1, 6) ] 
for t in threads: 
  t.start() 
 
for t in threads: 
  t.join() 
 
for i in range(5): 
  prec, value = q.get() 
  print prec, '\t', value 

This example creates a new context with the specified value, and then installs it into each thread.

Summarize


Related articles: