如何将Python的Decimal()类型转换为整数和指数

17

我想在Python中使用Decimal()数据类型,并将其转换为整数和指数,以便我可以将该数据以完全精度和十进制控制的形式发送到微控制器/PLC。https://docs.python.org/2/library/decimal.html

我已经使其工作,但这是一种hackish的方式;有人知道更好的方法吗?如果没有,我应该如何编写一个更低级别的"as_int()"函数呢?

示例代码:

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

对于那些没有编写过PLC程序的人,我的替代方法是使用int并在两个系统中声明小数点,或者使用浮点数(只有一些PLC支持)且存在精度损失。因此,您可以看到为什么能够做到这一点会很棒!感谢您的帮助!

太棒了!谢谢大家!我采用了rvraghav93的性能代码,并添加了每个人在这里回复的代码(http://paste.ubuntu.com/7856669/),以下是详细说明: rvraghav93: 1.11100006104 ericnutsch: 4.22099995613 smesseim: 4.70300006866 Mark_Ransom: 7.80999994278 Ehsan_Abd: 10.6519999504 - ericnutsch
4个回答

8
你可以这样做:

【这种方法比其他方法快3倍】

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

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

使用字符串解析方法所需的时间为: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

将数据转换为元组并提取方法所需的时间: 4.67159295082


你成功地绕过了 as_tuple() 函数,从而大幅提高了性能!感谢你的基准测试! - ericnutsch
1
FYI:在Python3.5中仍然适用。 - amohr
1
@ericnutsch我绝不会使用time.time来计时,它的精度不够。使用timeit.timeit,我得到了0.31839284114539623和1.5341496635228395对于to_int_exp和to_int_exp1。我不知道为什么我的结果会如此截然不同,也许是因为这是Python 3.8.6。 - Mark Ransom

5
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

谢谢,这正是我正在寻找的。 - Artem Baskakov

3

直接从元组中获取指数:

exponent = d.as_tuple()[2]

然后乘以10的适当次幂:

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

把所有内容整合起来:
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

0
from decimal import *
d=Decimal('3.14159')
t=d.as_tuple()
digits=t.digits
theInteger=0
for x in range(len(digits)):
   theInteger=theInteger+digits[x]*10**(len(digits)-x)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接