web-dev-qa-db-ja.com

Pythonでの浮動小数点の末尾ゼロなしのフォーマット

後続のゼロが含まれないようにフロートをフォーマットするにはどうすればよいですか?つまり、結果の文字列をできるだけ短くする必要があります。

例えば:

3 -> "3"
3. -> "3"
3.0 -> "3"
3.1 -> "3.1"
3.14 -> "3.14"
3.140 -> "3.14"
154
TarGz

私、('%f' % x).rstrip('0').rstrip('.')-科学表記法などではなく、固定小数点形式を保証します。ええ、%gほど滑らかでエレガントではありませんが、機能します(そして、私はしません) %gに科学表記法を使用しないように強制する方法を知っている;-)。

162
Alex Martelli

%gを使用してこれを実現できます。

'%g'%(3.140)

または、Python 2.6以降の場合:

'{0:g}'.format(3.140)

docs for formatgの原因(特に)

仮数から後続の無意味なゼロが削除され、その後に数字が残っていない場合は小数点も削除されます。

128
unutbu

最も簡単でおそらく最も効果的なアプローチを試してみてはどうですか?メソッドnormalize()は、右端のすべてのゼロを削除します。

from decimal import Decimal

print (Decimal('0.001000').normalize())
# Result: 0.001

Python 2およびPythonで動作します。

-更新-

@ BobStein-VisiBoneが指摘した唯一の問題は、10、100、1000 ...などの数字が指数表現で表示されることです。これは、代わりに次の関数を使用して簡単に修正できます。

from decimal import Decimal


def format_float(f):
    d = Decimal(str(f));
    return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
12
Ander

いくつかの同様の質問への回答を見た後、これは私にとって最良の解決策のようです:

def floatToString(inputValue):
    return ('%.15f' % inputValue).rstrip('0').rstrip('.')

私の推論:

%gは科学表記法を取り除きません。

>>> '%g' % 0.000035
'3.5e-05'

小数点以下15桁は、奇妙な動作を避けているようで、私のニーズに十分な精度を持っています。

>>> ('%.15f' % 1.35).rstrip('0').rstrip('.')
'1.35'
>>> ('%.16f' % 1.35).rstrip('0').rstrip('.')
'1.3500000000000001'

'%.15f' % inputValueの代わりにformat(inputValue, '.15f').を使用することもできましたが、それは少し遅くなります(〜30%)。

Decimal(inputValue).normalize()を使用することもできましたが、これにはいくつかの問題もあります。 1つは、かなり遅い(〜11x)ことです。また、非常に高い精度を備えていますが、normalize()を使用すると精度が低下することがわかりました。

>>> Decimal('0.21000000000000000000000000006').normalize()
Decimal('0.2100000000000000000000000001')
>>> Decimal('0.21000000000000000000000000006')
Decimal('0.21000000000000000000000000006')

最も重要なことは、Decimalからfloatに変換することです。これにより、そこに入れた数字以外のものになってしまいます。 Decimalは、算術がDecimalにとどまり、Decimalが文字列で初期化されている場合に最適に機能すると思います。

>>> Decimal(1.35)
Decimal('1.350000000000000088817841970012523233890533447265625')
>>> Decimal('1.35')
Decimal('1.35')

Decimal.normalize()の精度の問題は、コンテキスト設定を使用して必要なものに調整できると確信していますが、すでに低速であり、ばかげた精度を必要とせず、フロートから変換して失われることを考慮していますとにかく精度は追求する価値があるとは思いませんでした。

-0.0は有効な浮動小数点数であり、おそらくまれにしか発生しないため、「-0」の結果の可能性は気にしませんが、文字列の結果を可能な限り短くしたいということを述べたので、わずかな追加の速度コストで、常に追加の条件を使用できます。

def floatToString(inputValue):
    result = ('%.15f' % inputValue).rstrip('0').rstrip('.')
    return '0' if result == '-0' else result
10
PolyMesh

ここに私のために働いたソリューションがあります。 solution byPolyMeshと新しい.format()syntax の使用のブレンドです=。

for num in 3, 3., 3.0, 3.1, 3.14, 3.140:
    print('{0:.2f}'.format(num).rstrip('0').rstrip('.'))

出力

3
3
3
3.1
3.14
3.14
6
Kaushal Modi

ほとんどのPythonの方法でフォーマットが行われる可能性がありますが、ここに more_itertools.rstrip ツールを使用した代替ソリューションがあります。

import more_itertools as mit


def fmt(num, pred=None):
    iterable = str(num)
    predicate = pred if pred is not None else lambda x: x in {".", "0"}
    return "".join(mit.rstrip(iterable, predicate))

assert fmt(3) == "3"
assert fmt(3.) == "3"
assert fmt(3.0) == "3"
assert fmt(3.1) == "3.1"
assert fmt(3.14) == "3.14"
assert fmt(3.140) == "3.14"
assert fmt(3.14000) == "3.14"
assert fmt("3,0", pred=lambda x: x in set(",0")) == "3"

数値は文字列に変換され、述部を満たす後続文字が削除されます。関数定義fmtは必須ではありませんが、ここでは、すべて合格するアサーションをテストするために使用されます。注:文字列入力で機能し、オプションの述語を受け入れます。

このサードパーティライブラリの詳細も参照してください more_itertools

2
pylang
>>> str(a if a % 1 else int(a))
2
Shameem

これを実現するには、単にformat()を使用します。

format(3.140, '.10g')ここで、10は必要な精度です。

2
clel

3.と3.0が「3.0」として表示される場合、フロート表現からゼロを右にストリップする非常に単純なアプローチです。

print("%s"%3.140)

(例外を指摘してくれた@ellimilialに感謝)

1
drevicko

OPは、余分なゼロを削除し、結果の文字列をできるだけ短くしたいと考えています。

%g指数形式は、非常に大きい値と非常に小さい値の結果の文字列を短縮することがわかります。問題は、128.0のように指数表記を必要としない値に対して発生します。128.0は非常に大きくも小さくもありません。

Decimal.normalizeが長すぎる文字列を作成する場合にのみ、%g指数表記を使用する短い文字列として数値をフォーマットする1つの方法を次に示します。これは最速のソリューションではないかもしれません(Decimal.normalizeを使用するため)

def floatToString (inputValue, precision = 3):
    rc = str(Decimal(inputValue).normalize())
    if 'E' in rc or len(rc) > 5:
        rc = '{0:.{1}g}'.format(inputValue, precision)        
    return rc

inputs = [128.0, 32768.0, 65536, 65536 * 2, 31.5, 1.000, 10.0]

outputs = [floatToString(i) for i in inputs]

print(outputs)

# ['128', '32768', '65536', '1.31e+05', '31.5', '1', '10']
0
kinok

フロートの場合、これを使用できます:

def format_float(num):
    return ('%i' if num == int(num) else '%s') % num

試して:

>>> format_float(1.00000)
'1'
>>> format_float(1.1234567890000000000)
'1.123456789'

10進数については、こちらの解決策を参照してください: https://stackoverflow.com/a/42668598/591754

0

%fを処理します。

%.2f

、ここで:.2f == .00 floats。

例:

「価格:%.2f」%価格[製品]を印刷

出力:

価格:1.50

0
Alex M.