以工程格式打印编号

jmu*_*ufo 14 python decimal python-2.7

我试图用python将数字打印成工程格式,但我似乎无法让它工作.语法SEEMS足够简单,但它不起作用.

>>> import decimal 
>>> x = decimal.Decimal(1000000)
>>> print x
1000000
>>>> print x.to_eng_string() 
1000000
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚为什么会这样.这两个值不相等(一个是字符串,另一个是int).设置各种上下文decimal似乎也没有帮助.任何线索或想法?

pax*_*blo 21

要使其工作,您必须首先规范化小数:

>>> x = decimal.Decimal ('10000000')

>>> x.normalize()
Decimal('1E+7')

>>> x.normalize().to_eng_string()
'10E+6'
Run Code Online (Sandbox Code Playgroud)

可以通过深入研究源代码来发现其原因.

如果你to_eng_string()在Python 2.7.3源代码树中检查(Lib/decimal.py来自这里的gzip源tar球),它只需__str__使用engset 调用true即可.

然后,您可以看到它决定了最初使用小数点左边有多少位数:

leftdigits = self._exp + len(self._int)
Run Code Online (Sandbox Code Playgroud)

下表显示了这两个值的值:

                         ._exp       ._int         len   leftdigits
                         -----       ---------     ---   ----------
Decimal (1000000)            0       '1000000'       7            7
Decimal ('1E+6')             6       '1'             1            7
Run Code Online (Sandbox Code Playgroud)

之后继续的代码是:

if self._exp <= 0 and leftdigits > -6:
    # no exponent required
    dotplace = leftdigits
elif not eng:
    # usual scientific notation: 1 digit on left of the point
    dotplace = 1
elif self._int == '0':
    # engineering notation, zero
    dotplace = (leftdigits + 1) % 3 - 1
else:
    # engineering notation, nonzero
    dotplace = (leftdigits - 1) % 3 + 1
Run Code Online (Sandbox Code Playgroud)

你可以看到,除非它已经在某个范围()中一个指数,否则self._exp > 0 or leftdigits <= -6在字符串表示中都不会给它.


进一步调查显示了这种行为的原因.查看代码本身,您将看到它基于General Decimal Arithmetic Specification(PDF 这里).

如果您搜索该文档to-scientific-string(基于该文档的to-engineering-string基础很重),则会部分说明(转述,并使用我的粗体位):

如果需要指数,"to-scientific-string"操作将数字转换为字符串,使用科学记数法.该操作不受上下文的影响.

如果数字是有限数,那么:

系数首先使用字符0到9转换为十进制字符串,不带前导零(除非它的值为零,在这种情况下使用单个0字符).

接下来,计算调整后的指数; 这是指数,加上转换系数中的字符数,减去一个.也就是说,指数+(clength-1),其中clength是十进制数字系数的长度.

如果指数小于或等于零且调整后的指数大于或等于-6,则该数字将转换为字符形式,而不使用指数表示法.在这种情况下,如果指数为零,则不添加小数点.否则(指数将为负数),将插入一个小数点,指数的绝对值指定小数点右侧的字符数.必要时,在转换后的系数的左侧添加"0"字符.如果在插入之后没有字符在小数点之前,则以常规的"0"字符作为前缀.

换句话说,它正在做它正在做的事情,因为这是标准告诉它做的事情.

  • @jmurrayufo,检查更新.基本上,它正在这样做,因为这是标准告诉它做的事情. (2认同)

sli*_*led 8

我意识到这是一个旧线程,但它确实接近搜索的顶部python engineering notation.

我是一名喜欢"工程101"工程单位的工程师.我甚至不喜欢这样的名称0.1uF,我想要阅读100nF.我玩这个Decimal类,并不喜欢它在可能的值范围内的行为,所以我推出了一个名为engineering_notationpip-installable 的包.

pip install engineering_notation
Run Code Online (Sandbox Code Playgroud)

从Python内部:

>>> from engineering_notation import EngNumber
>>> EngNumber('1000000')
1M
>>> EngNumber(1000000)
1M
>>> EngNumber(1000000.0)
1M
>>> EngNumber('0.1u')
100n
>>> EngNumber('1000m')
1
Run Code Online (Sandbox Code Playgroud)

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

https://github.com/slightlynybbled/engineering_notation


med*_*duz 6

有一个使用内置printf 样式字符串格式的解决方案

我假设(及时向前)您现在使用内置的 python 3,因为所有格式化都大大简化和规范化(我建议将此备忘单添加为书签

In [1]: myfloat = 0.000000001
In [2]: print(f'{myfloat:g}')
1e-09
Run Code Online (Sandbox Code Playgroud)

旧的语法(适用于 python 2)是:

In [17]: '%g' % myfloat
Out[17]: '1e-09'
Run Code Online (Sandbox Code Playgroud)

另一种不错的格式是:

In [3]: print(f'{myfloat:E}')
1.000000E-09
Run Code Online (Sandbox Code Playgroud)

您可以对输出进行一些控制:

In [4]: print(f'{myfloat:.3E}')
1.000E-09
Run Code Online (Sandbox Code Playgroud)

  • 这是科学计数法,不是工程计数法。在工程符号中,指数始终是 3 的倍数。 (2认同)