これが私を悩ませている例です:
>>> x = decimal.Decimal('0.0001')
>>> print x.normalize()
>>> print x.normalize().to_eng_string()
0.0001
0.0001
ミリ (10e-3) とマイクロ (10e-6) を表す工学表記法を持つ方法はありますか?
これが私を悩ませている例です:
>>> x = decimal.Decimal('0.0001')
>>> print x.normalize()
>>> print x.normalize().to_eng_string()
0.0001
0.0001
ミリ (10e-3) とマイクロ (10e-6) を表す工学表記法を持つ方法はありますか?
以下は、明示的に処理を行う関数で、指数に 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)
編集: Matplotlib はエンジニアリング フォーマッタを実装しているため、1 つのオプションは Matplotlibs フォーマッタを直接使用することです。
import matplotlib as mpl
formatter = mpl.ticker.EngFormatter()
formatter(10000)
result: '10 k'
元の答え:
Julian Smith の優れた回答 (およびこの回答) に基づいて、次の点を改善するために関数を変更しました。
更新された関数は次のとおりです。
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)
decimal
モジュールはDecimal Arithmetic Specificationに従っており、次のように述べられています。
to-scientific-string – 数値文字列への変換
[...]
係数は、最初に 0 から 9 までの文字を使用して 10 進数の文字列に変換されます (値がゼロの場合は例外で、その場合は単一の 0 文字が使用されます)。次に、調整された指数が計算されます。これは、指数に、変換された係数の文字数を足して 1 を引いたものです。つまり、指数 + (clength-1) であり、clength は係数の長さ (10 進数) です。
指数が 0 以下で、調整後の指数が -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
このdecimal
モジュールは、独自の(IBM) Decimal Arithmetic Specification に従っています。
この IBM 仕様全体を引用すると、何が問題なのかが明確にわかりますdecimal.to_eng_string()
(強調を追加)。
to-engineering-string – 数値文字列への変換
この操作は、指数が必要な場合に工学表記法を使用して数値を文字列に変換します。
変換は、指数表記が使用される有限数の場合を除いて、科学数値文字列への変換の規則に正確に従います。この場合、変換された指数は、小数点の前に 1、2、または 3 文字を配置することによって 3 の倍数(工学表記法)になるように調整されます(つまり、小数点の前の部分は 1 から 999 の範囲になります)。 )。これには、1 つまたは 2 つの末尾のゼロの追加が必要になる場合があります。
調整後に小数点の後に数字が続かない場合、小数点は追加されません。最後の指数がゼロの場合、標識文字と指数はサフィックスされません。
この独自の IBM 仕様は、実際には無限小数表現の数値に工学表記法を適用しないことを認めており、代わりに通常の科学表記法が使用されています! これは明らかに正しくない動作であり、Python のバグ レポートが開かれました。
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
上記の回答と同様ですが、もう少しコンパクトです。
from math import log10, floor
def eng_format(x,precision=3):
"""Returns string in engineering format, i.e. 100.1e-3"""
x = float(x) # inplace copy
if x == 0:
a,b = 0,0
else:
sgn = 1.0 if x > 0 else -1.0
x = abs(x)
a = sgn * x / 10**(floor(log10(x)))
b = int(floor(log10(x)))
if -3 < b < 3:
return ("%." + str(precision) + "g") % x
else:
a = a * 10**(b % 3)
b = b - b % 3
return ("%." + str(precision) + "gE%s") % (a,b)
トライアル:
In [10]: eng_format(-1.2345e-4,precision=5)
Out[10]: '-123.45E-6'