Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Convert pythons Decimal() type into an INT and exponent

I would like to use the Decimal() data type in python and convert it to an integer and exponent so I can send that data to a microcontroller/plc with full precision and decimal control. https://docs.python.org/2/library/decimal.html

I have got it to work, but it is hackish; does anyone know a better way? If not what path would I take to write a lower level "as_int()" function myself?

Example code:

from decimal import *
d=Decimal('3.14159')
t=d.as_tuple()
if t[0] == 0:
    sign=1
else:
    sign=-1

digits= t[1]
theExponent=t[2]
theInteger=sign * int(''.join(map(str,digits)))

theExponent
theInteger

For those that havent programmed PLCs, my alternative to this is to use an int and declare the decimal point in both systems or use a floating point (that only some PLCs support) and is lossy. So you can see why being able to do this would be awesome!

Thanks in advance!

like image 430
ericnutsch Avatar asked Jul 24 '14 22:07

ericnutsch


3 Answers

from functools import reduce   # Only in Python 3, omit this in Python 2.x
from decimal import *

d = Decimal('3.14159')
t = d.as_tuple()

theInteger = reduce(lambda rst, x: rst * 10 + x, t.digits)
theExponent = t.exponent
like image 82
smesseim Avatar answered Sep 27 '22 18:09

smesseim


Get the exponent directly from the tuple as you were:

exponent = d.as_tuple()[2]

Then multiply by the proper power of 10:

i = int(d * Decimal('10')**-exponent)

Putting it all together:

from decimal import Decimal

_ten = Decimal('10')

def int_exponent(d):
    exponent = d.as_tuple()[2]
    int_part = int(d * (_ten ** -exponent))
    return int_part, exponent
like image 20
Mark Ransom Avatar answered Sep 27 '22 16:09

Mark Ransom


You could do this :

[ This is 3 times faster than the other methods ]

d=Decimal('3.14159')

list_d = str(d).split('.')   
# Converting the decimal to string and splitting it at the decimal point

# If decimal point exists => Negative exponent
# i.e   3.14159 => "3", "14159"
# exponent = -len("14159") = -5
# integer = int("3"+"14159") = 314159

if len(list_d) == 2:
    # Exponent is the negative of length of no of digits after decimal point
    exponent = -len(list_d[1])
    integer = int(list_d[0] + list_d[1])



# If the decimal point does not exist => Positive / Zero exponent
# 3400
# exponent = len("3400") - len("34") = 2
# integer = int("34") = 34

else:
    str_dec = list_d[0].rstrip('0')
    exponent = len(list_d[0]) - len(str_dec)
    integer = int(str_dec)

print integer, exponent

Performance testing

def to_int_exp(decimal_instance):

    list_d = str(decimal_instance).split('.')

    if len(list_d) == 2:
        # Negative exponent
        exponent = -len(list_d[1])
        integer = int(list_d[0] + list_d[1])

    else:
        str_dec = list_d[0].rstrip('0')
        # Positive exponent
        exponent = len(list_d[0]) - len(str_dec)
        integer = int(str_dec)

    return integer, exponent

def to_int_exp1(decimal_instance):
    t=decimal_instance.as_tuple()

    if t[0] == 0:
        sign=1
    else:
        sign=-1

    digits= t[1]

    exponent = t[2]

    integer = sign * int(''.join(map(str,digits)))

    return integer, exponent
Calculating the time taken for 100,000 loops for both methods :
ttaken = time.time()
for i in range(100000):
    d = Decimal(random.uniform(-3, +3))
    to_int_exp(d)    
ttaken = time.time() - ttaken
print ttaken

Time taken for string parsing method : 1.56606507301

ttaken = time.time()
for i in range(100000):
    d = Decimal(random.uniform(-3, +3))
    to_int_exp1(d)    
ttaken = time.time() - ttaken
print ttaken

Time taken for convertion to tuple then extract method : 4.67159295082

like image 25
Raghav RV Avatar answered Sep 27 '22 16:09

Raghav RV