I was just playing around with Decimals with Numpy.
I found that Numpy offers a function called np.vectorize that allows you to take a function and apply it over a numpy array.
In [23]:
import numpy as np
import decimal
D = decimal.Decimal
We'll create a regular np float array
In [24]:
f10 = np.random.ranf(10)
f10
Out[24]:
array([ 0.45410583, 0.35353919, 0.5976785 , 0.12030978, 0.00976334,
0.47035594, 0.76010096, 0.09229687, 0.24842551, 0.30564141])
trying to convert the array using np.asarray to Decimal type doesn't work. It seems that trying to use np.asarray and specifying the decimal.Decimal type sets the array to object which is to be expected but if you actually access an individual element of the array it still has a float data type.
In [25]:
f10todec = np.asarray(f10, dtype = decimal.Decimal)
print f10todec.dtype, f10todec
print type(f10todec[0])
object [0.454105831376884 0.3535391906233327 0.5976785016396975 0.1203097778312584
0.009763339031407026 0.47035593879363524 0.7601009625324361
0.09229687387940333 0.24842550566826282 0.30564141425653435]
<type 'float'>
If you give np.array a homogenous python list of Decimal types then it seems to preserve the type, hense the list comprehension below to get a list of the values in the first array as Decimal datatype. So I had to make the decimal array this way.
In [26]:
D10 = np.array([D(d) for d in f10])
D10
Out[26]:
array([Decimal('0.4541058313768839838076019077561795711517333984375'),
Decimal('0.35353919062333272194109667907468974590301513671875'),
Decimal('0.597678501639697490332991947070695459842681884765625'),
Decimal('0.12030977783125840208100498784915544092655181884765625'),
Decimal('0.00976333903140702563661079693702049553394317626953125'),
Decimal('0.47035593879363524205672320022131316363811492919921875'),
Decimal('0.76010096253243608632743644193396903574466705322265625'),
Decimal('0.09229687387940332943259136300184763967990875244140625'),
Decimal('0.24842550566826282487653543284977786242961883544921875'),
Decimal('0.30564141425653434946951847450691275298595428466796875')], dtype=object)
basic math operations seem to work ok
In [27]:
D10/2
Out[27]:
array([Decimal('0.2270529156884419919038009539'),
Decimal('0.1767695953116663609705483395'),
Decimal('0.2988392508198487451664959735'),
Decimal('0.06015488891562920104050249392'),
Decimal('0.004881669515703512818305398469'),
Decimal('0.2351779693968176210283616001'),
Decimal('0.3800504812662180431637182210'),
Decimal('0.04614843693970166471629568150'),
Decimal('0.1242127528341314124382677164'),
Decimal('0.1528207071282671747347592373')], dtype=object)
In [28]:
np.sqrt(D10)
Out[28]:
array([Decimal('0.6738737503248542354573624759'),
Decimal('0.5945916166776426405934196108'),
Decimal('0.7730966961769384578392278689'),
Decimal('0.3468569991095154505863255680'),
Decimal('0.09880961001545864636229121433'),
Decimal('0.6858250059553349663476168402'),
Decimal('0.8718376927688066448819998853'),
Decimal('0.3038040057000620415496242404'),
Decimal('0.4984230187985531079935481296'),
Decimal('0.5528484550548498633920483390')], dtype=object)
Untill you try a trig function for which there is no corresponding function in the decimal module
In [29]:
np.sin(D10)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-29-31ba62da35b8> in <module>()
----> 1 np.sin(D10)
AttributeError: 'Decimal' object has no attribute 'sin'
so lets use np.vectorize so we can use decimal's quantize function to do rounding.
In [30]:
npquantize = np.vectorize(decimal.Decimal.quantize)
qnt_D10 = npquantize(D10, D('.000001'))
qnt_D10
Out[30]:
array([Decimal('0.454106'), Decimal('0.353539'), Decimal('0.597679'),
Decimal('0.120310'), Decimal('0.009763'), Decimal('0.470356'),
Decimal('0.760101'), Decimal('0.092297'), Decimal('0.248426'),
Decimal('0.305641')], dtype=object)
You also need to be careful about some regular python math functions because they will automaticaly change the return type to float. I assume this is because the number can't be calculated accuratly based on the function like SIN or COS.
so i guess the short answer is use a list comprehension to get and convert the items in a numpy array to a python list then create that array from the list of Decimals.
To return numpy arrays with their type intact I guess you could use the vectorize function to wrap any function that works with Decimal type to apply over the np array.
On a side note there is a module in the pip that provides numpy style arrays with IEEE Decimals https://pypi.python.org/pypi/decimalpy/0.1