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