Python Decimal - mili(10e-3)和micro(10e-6)的工程符号

时间:2013-07-31 14:32:24

标签: python python-2.7 decimal

以下是困扰我的例子:

>>> x = decimal.Decimal('0.0001')
>>> print x.normalize()
>>> print x.normalize().to_eng_string()
0.0001
0.0001

有没有办法用工程符号表示mili(10e-3)和micro(10e-6)?

5 个答案:

答案 0 :(得分:9)

这是一个明确地执行操作的函数,并且还支持为指数使用SI后缀:

def eng_string( x, format='%s', si=False):
    '''
    Returns float/int value <x> formatted in a simplified engineering format -
    using an exponent that is a multiple of 3.

    format: printf-style string used to format the value before the exponent.

    si: if true, use SI suffix for exponent, e.g. k instead of e3, n instead of
    e-9 etc.

    E.g. with format='%.2f':
        1.23e-08 => 12.30e-9
             123 => 123.00
          1230.0 => 1.23e3
      -1230000.0 => -1.23e6

    and with si=True:
          1230.0 => 1.23k
      -1230000.0 => -1.23M
    '''
    sign = ''
    if x < 0:
        x = -x
        sign = '-'
    exp = int( math.floor( math.log10( x)))
    exp3 = exp - ( exp % 3)
    x3 = x / ( 10 ** exp3)

    if si and exp3 >= -24 and exp3 <= 24 and exp3 != 0:
        exp3_text = 'yzafpnum kMGTPEZY'[ ( exp3 - (-24)) / 3]
    elif exp3 == 0:
        exp3_text = ''
    else:
        exp3_text = 'e%s' % exp3

    return ( '%s'+format+'%s') % ( sign, x3, exp3_text)

答案 1 :(得分:6)

decimal模块跟随Decimal Arithmetic Specification,其中声明:

  

to-scientific-string - 转换为数字字符串

     

[...]

     

首先使用字符0到9将系数转换为十进制的字符串,不带前导零(除非它的值为零,在这种情况下使用单个0字符)。   接下来,计算调整后的指数;这是指数,加上转换系数中的字符数,减去一个。也就是说,指数+(clength-1),其中clength是十进制数字系数的长度。

     

如果指数小于或等于零且调整后的指数大于或等于-6,则该数字将被转换   不使用指数表示法的字符形式。

     

[...]

     

to-engineering-string - 转换为数字字符串

     

此操作使用工程将数字转换为字符串   如果需要指数,则表示法。

     

转化 完全遵循转换为科学的规则   数字字符串 除了有限数字的情况,其中指数   使用符号。

或者换句话说:

>>> for n in (10 ** e for e in range(-1, -8, -1)):
...     d = Decimal(str(n))
...     print d.to_eng_string()
... 
0.1
0.01
0.001
0.0001
0.00001
0.000001
100E-9

答案 2 :(得分:5)

修改 Matplotlib实现了工程格式化程序,因此一种选择是直接使用Matplotlibs格式化程序,例如:

import matplotlib as mpl
formatter = mpl.ticker.EngFormatter()
formatter(10000)

result: '10 k'

原始回答:

根据Julian Smith的优秀答案(和this回答),我改变了功能以改进以下几点:

  • Python3兼容(整数除法)
  • 兼容0输入
  • 舍入为大量数字,默认为3,不打印尾随零

所以这里有更新的功能:

import math
def eng_string( x, sig_figs=3, si=True):
    """
    Returns float/int value <x> formatted in a simplified engineering format -
    using an exponent that is a multiple of 3.

    sig_figs: number of significant figures

    si: if true, use SI suffix for exponent, e.g. k instead of e3, n instead of
    e-9 etc.
    """
    x = float(x)
    sign = ''
    if x < 0:
        x = -x
        sign = '-'
    if x == 0:
        exp = 0
        exp3 = 0
        x3 = 0
    else:
        exp = int(math.floor(math.log10( x )))
        exp3 = exp - ( exp % 3)
        x3 = x / ( 10 ** exp3)
        x3 = round( x3, -int( math.floor(math.log10( x3 )) - (sig_figs-1)) )
        if x3 == int(x3): # prevent from displaying .0
            x3 = int(x3)

    if si and exp3 >= -24 and exp3 <= 24 and exp3 != 0:
        exp3_text = 'yzafpnum kMGTPEZY'[ exp3 // 3 + 8]
    elif exp3 == 0:
        exp3_text = ''
    else:
        exp3_text = 'e%s' % exp3

    return ( '%s%s%s') % ( sign, x3, exp3_text)

答案 3 :(得分:5)

我意识到这是一个旧线程,但它确实接近搜索python engineering notation的顶部,并且将此信息放在此处似乎是谨慎的。

我是一名喜欢&#34;工程101&#34;工程单位。我甚至不喜欢0.1uF这样的名称,我想要阅读100nF。我使用Decimal类并且并不喜欢它在可能值范围内的行为,因此我推出了一个名为engineering_notation的可以进行pip安装的包。

pip install engineering_notation

从Python中:

>>> from engineering_notation import EngNumber
>>> EngNumber('1000000')
1M
>>> EngNumber(1000000)
1M
>>> EngNumber(1000000.0)
1M
>>> EngNumber('0.1u')
100n
>>> EngNumber('1000m')
1

该软件包还支持比较和其他简单的数值运算。

https://github.com/slightlynybbled/engineering_notation

答案 4 :(得分:3)

«完整»引用显示错误!

decimal模块确实遵循专有(IBM)Decimal Arithmetic Specification. 引用此IBM规范完整清楚地显示了decimal.to_eng_string()的错误(强调添加):

  

to-engineering-string - 转换为数字字符串

     

此操作使用工程将数字转换为字符串   如果需要指数,则表示法。

     

转化 完全遵循转换为科学的规则   数字字符串 ,但有限数字的情况除外,其中指数   使用符号。在这种情况下,通过将小数点放在其前面的一个,两个或三个字符(即小数点前面的部分),将转换的指数调整为三个(工程符号)的倍数点数范围从1到999)。这可能需要添加一个或两个尾随零。

     

如果在调整后小数点后面没有数字,则不会添加。如果最终指数为零,那么后缀没有指示字母和指数。

这种专有的IBM规范实际上承认不对具有infinite decimal representation的数字应用工程符号,而是使用普通的科学记数法!这显然是错误的行为,Python bug report被打开了。

解决方案

from math import floor, log10

def powerise10(x):
    """ Returns x as a*10**b with 0 <= a < 10
    """
    if x == 0: return 0,0
    Neg = x < 0
    if Neg: x = -x
    a = 1.0 * x / 10**(floor(log10(x)))
    b = int(floor(log10(x)))
    if Neg: a = -a
    return a,b

def eng(x):
    """Return a string representing x in an engineer friendly notation"""
    a,b = powerise10(x)
    if -3 < b < 3: return "%.4g" % x
    a = a * 10**(b % 3)
    b = b - b % 3
    return "%.4gE%s" % (a,b)

来源:https://code.activestate.com/recipes/578238-engineering-notation/

测试结果

>>> eng(0.0001)
100E-6