我正在尝试使用 python 将数字打印成工程格式,但我似乎无法让它工作。语法看起来很简单,但它就是行不通。
>>> import decimal
>>> x = decimal.Decimal(1000000)
>>> print x
1000000
>>>> print x.to_eng_string()
1000000
我不知道为什么会这样。这两个值不相等(一个是字符串,另一个是 int)。设置各种上下文decimal
似乎也无济于事。有什么线索或想法吗?
我正在尝试使用 python 将数字打印成工程格式,但我似乎无法让它工作。语法看起来很简单,但它就是行不通。
>>> import decimal
>>> x = decimal.Decimal(1000000)
>>> print x
1000000
>>>> print x.to_eng_string()
1000000
我不知道为什么会这样。这两个值不相等(一个是字符串,另一个是 int)。设置各种上下文decimal
似乎也无济于事。有什么线索或想法吗?
为了让它工作,你必须先标准化小数:
>>> x = decimal.Decimal ('10000000')
>>> x.normalize()
Decimal('1E+7')
>>> x.normalize().to_eng_string()
'10E+6'
可以通过深入研究源代码来发现其原因。
如果您to_eng_string()
在 Python 2.7.3 源代码树中检查(Lib/decimal.py
来自 gzipped 源 tar 球here__str__
),它只需调用eng
set 为 true。
然后你可以看到它决定了小数点左边的位数最初是:
leftdigits = self._exp + len(self._int)
下表显示了这两件事的值:
._exp ._int len leftdigits
----- --------- --- ----------
Decimal (1000000) 0 '1000000' 7 7
Decimal ('1E+6') 6 '1' 1 7
之后继续的代码是:
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
你可以看到,除非它已经在某个范围内有一个指数(self._exp > 0 or leftdigits <= -6
进一步的调查显示了这种行为的原因。查看代码本身,您会发现它基于(此处General Decimal Arithmetic Specification
为PDF )。
如果您搜索该文档to-scientific-string
(基于该文档to-engineering-string
),它会部分说明(转述,并用我的粗体字):
“to-scientific-string”操作将数字转换为字符串,如果需要指数,则使用科学记数法。操作不受上下文影响。
如果该数是有限数,则:
首先将系数转换为以 10 为底的字符串,使用字符 0 到 9,不带前导零(除非它的值为零,在这种情况下使用单个 0 字符)。
接下来,计算调整后的指数;这是指数加上转换系数中的字符数减去一。也就是说,exponent+(clength-1),其中 clength 是十进制数字的系数长度。
如果指数小于或等于零且调整后的指数大于或等于-6,则该数字将转换为字符形式而不使用指数表示法。在这种情况下,如果指数为零,则不添加小数点。否则(指数将为负数),将插入一个小数点,其中指数的绝对值指定小数点右侧的字符数。必要时将“0”字符添加到转换系数的左侧。如果在此插入之后小数点之前没有字符,则以传统的“0”字符为前缀。
换句话说,它正在做它正在做的事情,因为这是标准告诉它要做的事情。
我意识到这是一个旧线程,但它确实接近搜索的顶部python engineering notation
。
我是一个喜欢“工程101”工程单元的工程师。我什至不喜欢诸如0.1uF
, I want that read之类的名称100nF
。我玩过这个Decimal
类,并不喜欢它在可能值范围内的行为,所以我推出了一个名为engineering_notation
pip-installable 的包。
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
这个包还支持比较和其他简单的数值运算。
在我看来,您将不得不自己动手:
from math import log10
def eng_str(x):
y = abs(x)
exponent = int(log10(y))
engr_exponent = exponent - exponent%3
z = y/10**engr_exponent
sign = '-' if x < 0 else ''
return sign+str(z)+'e'+str(engr_exponent)
尽管您可能希望在该部分的格式方面更加小心z
......
没有经过很好的测试。如果发现错误,请随时编辑
有一个使用内置printf-style String Formatting的解决方案
我将假设(及时)您现在使用内置的 python 3,因为所有的格式都大大简化和规范化了(我建议将此备忘单添加书签。
In [1]: myfloat = 0.000000001
In [2]: print(f'{myfloat:g}')
1e-09
较旧的语法(适用于 python 2)是:
In [17]: '%g' % myfloat
Out[17]: '1e-09'
另一个不错的格式是:
In [3]: print(f'{myfloat:E}')
1.000000E-09
您可以对其输出进行一些控制:
In [4]: print(f'{myfloat:.3E}')
1.000E-09
QuantiPhy是另一个可以帮助您解决此问题的软件包。QuantiPhy提供了Quantity类,用于将值和单位组合到一个对象中。它可以以多种方式格式化数量。通常人们使用 SI 比例因子,但也支持工程形式。安装:
pip3 install quantiphy
您可以从数字或字符串开始创建Quantity对象:
>>> from quantiphy import Quantity
>>> q = Quantity(10000000)
>>> q.render(form='eng')
'10e6'
默认情况下, QuantiPhy使用 SI 表示法,但您可以将默认形式设置为 'eng':
>>> print(q)
10M
>>> Quantity.set_prefs(form='eng')
>>> print(q)
10e6
通常你会指定一个数量的单位:
>>> f = Quantity(10_000_000, 'Hz')
>>> print(f)
10e6 Hz
数量子类float,因此您可以在任何使用浮点数的地方使用数量。
QuantiPhy是一个功能强大的软件包,它得到了很好的支持和有据可查的文档。我鼓励你试一试。
matplotlib 也可以使用:
>>> from matplotlib.ticker import EngFormatter
>>> engFormat = EngFormatter()
>>> print(engFormat(1000))
1 k
我让您在https://matplotlib.org/stable/api/ticker_api.html中查看更多详细信息和选项 另一个更复杂的示例:
>>> from matplotlib.ticker import EngFormatter
>>> engFormat = EngFormatter(unit='Hz',places=2,sep='')
>>> print(engFormat(1000))
1.00kHz
现在是2020年了,伙计们!并且发生了 COVID-19 大流行。对于这种类型的工作,您必须使用 f 字符串文字:
使用python3.6.4及以上,你可以做到
a = 3e-4
print(f"{a:.0E}")