Sondaki sıfırlar olmadan yüzmeleri biçimlendirme


181

Bir şamandırayı, sonunda sıfır içermeyecek şekilde nasıl biçimlendirebilirim? Başka bir deyişle, ortaya çıkan dize mümkün olduğunca kısa olmasını istiyorum.

Örneğin:

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

Bu örnek hiç mantıklı değil. 3.14 == 3.140- Aynı kayan nokta numarası. Bu nedenle 3.140000 aynı kayan noktalı sayıdır. Sıfır ilk etapta mevcut değildir.
S.Lott

33
@ S.Lott - Bence sorun, iki sayının gerçek eşdeğeri değil, sondaki sıfırlar olmadan kayan sayıları YAZDIRMAK.
Mart'ta pokstad

1
@pokstad: Bu durumda, "gereksiz" sıfır yoktur. %0.2fve %0.3fsoldaki son sayıları üretmek için gereken iki biçimdir. %0.2fSağdaki son iki sayıyı üretmek için kullanın .
S.Lott

6
3.0 -> "3"hala geçerli bir kullanım durumudur. beklediğim gibi bir çıktı nerede ve ne zaman print( '{:,g}'.format( X )çıktı için benim için çalıştı . 3X = 6 / 2X = 5 / 22.5
ShoeMaker

1
eski soru, ama .. print("%s"%3.140)size ne istediğinizi verir. (Aşağıya bir cevap ekledim ...)
drevicko

Yanıtlar:


178

Ben, yapardım ('%f' % x).rstrip('0').rstrip('.')- bilimsel gösterim, vb. Yerine sabit noktalı biçimlendirmeyi garanti eder. Evet, kaygan ve zarif değil %g, ama işe yarıyor (ve %gasla bilimsel gösterimi kullanmaya zorlamayacağımı bilmiyorum ; -).


6
Bununla ilgili tek sorun '%.2f' % -0.0001sizi -0.00sonunda ve sonunda bırakacaktır -0.
Kos

3
@ alexanderlukanin13 varsayılan hassasiyet 6 olduğundan, bkz. docs.python.org/2/library/string.html : 'f' Fixed point. Displays the number as a fixed-point number. The default precision is 6.Yukarıdaki çözümde '% 0.7f' kullanmanız gerekir.
derenio

3
@derenio İyi bir nokta :-) Sadece yukarıdaki hassasiyeti yükseltmenin '%0.15f'kötü bir fikir olduğunu ekleyebilirim , çünkü garip şeyler olmaya başlar.
alexanderlukanin13

1
Başka bir dizenin ortasındaysanız: print('In the middle {} and something else'.format('{:f}'.format(a).rstrip('0')))
hataya dayanıklı

1
@Alex Martelli, çifte rstripkomuttan kurtul . .Daha sonra tek bir işlemle hem nokta ( ) hem de tüm arkadaki sıfırları çıkarmak için bunu kullanın :('%f' % x).rstrip('.0')
Gabriel Staples

143

Bunu %gbaşarmak için kullanabilirsiniz :

'%g'%(3.140)

veya Python 2.6 veya üstü için:

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

İçin dokümanlardanformat : gnedenler (diğer şeylerin yanı sıra)

önemsiz sondaki sıfırlar [kaldırılacak] önemden kaldırılır ve ondalık noktadan sonra kalan basamak yoksa da ondalık nokta kaldırılır.


28
Ah, neredeyse! Bazen şamandırayı bilimsel gösterimde biçimlendirir ("2.342E + 09") - kapatmak mümkün, yani her zaman tüm önemli basamakları gösterebilir mi?
TarGz

5
Neden kullanabileceğinizi '{0:...}'.format(value)kullanmalısınız format(value, '...')? Bu, biçim belirticiyi başka bir şekilde boş olan bir şablon dizesinden ayrıştırmak zorunda kalmaz.
Martijn Pieters

2
@MartijnPieters: Biçim belirleyicisini ayrıştırmadaki minik maliyet, diğer genel AFAICT tarafından gömülür; pratikte, 3.6'daki yerel kriterlerim (gerçek kodu doğru bir şekilde modellemek için mikro testin fonksiyon kapsamının belirlenmesi ile) format(v, '2.5f')~% 10 daha uzun sürdü '{:2.5f}'.format(v). Olmasa bile, stryöntem formunu kullanma eğilimindeyim, çünkü değiştirmem gerektiğinde, ek değerler eklemeliyim vb. Değiştirilecek daha az şey var. Tabii ki, 3.6 itibariyle çoğu amaç için f-stringlerimiz var. :-)
ShadowRanger

5
Python 3.6'da, bu değişken bir değişken olan f"{var:g}"yere kısaltılabilir var.
TheGreatCabbage

12

En kolay ve muhtemelen en etkili yaklaşımı denemeye ne dersiniz? Normalize () yöntemi , en sağdaki tüm sıfırları kaldırır.

from decimal import Decimal

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

Çalışıyor Python 2 ve Python 3 .

-- Güncellenmiş --

@ BobStein-VisiBone'un belirttiği gibi tek sorun, 10, 100, 1000 ... gibi sayıların üstel gösterimde görüntülenmesidir. Bu, aşağıdaki işlev kullanılarak kolayca sabitlenebilir:

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()

2
Dışında Decimal('10.0').normalize()olur'1E+1'
Bob Stein

11

Birkaç benzer sorunun cevabını inceledikten sonra, bu benim için en iyi çözüm gibi görünüyor:

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

Akıl yürütmem:

%g bilimsel gösterimden kurtulamaz.

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

15 ondalık basamak garip davranışlardan kaçınıyor gibi görünüyor ve ihtiyaçlarım için çok fazla hassasiyete sahip.

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

Bunun format(inputValue, '.15f').yerine kullanabilirdim '%.15f' % inputValue, ama bu biraz daha yavaş (~% 30).

Kullanabilirdim Decimal(inputValue).normalize(), ama bunun da birkaç sorunu var. Birincisi, çok daha yavaş (~ 11x). Ayrıca oldukça büyük bir hassasiyete sahip olmasına rağmen, kullanırken hala hassas kayıptan muzdarip olduğunu gördüm normalize().

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

En önemlisi, hala oraya koyduğunuz sayıdan başka bir şeyle sonuçlanmanıza neden olabilecek Decimalbirinden dönüştürüyorum float. Ben Decimalaritmetik kalır Decimalve Decimalbir dize ile başlatıldığında en iyi çalışır düşünüyorum .

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

Ben eminim hassas sorunu Decimal.normalize()bağlam ayarları kullanılarak gerekenlere ayarlanabilir, ancak zaten düşük hız ve saçma hassasiyete ihtiyaç duymadan ve yine de bir şamandıradan dönüştüğüm ve yine de hassasiyeti kaybettiğim düşünülürse, yapmadım takip etmeye değer olduğunu düşünmüyorum.

-0.0 geçerli bir kayan nokta sayısı olduğundan ve muhtemelen zaten nadir bir olay olacağı için olası "-0" sonucuyla ilgilenmiyorum, ancak bahsettiğinizden dolayı dize sonucunu mümkün olduğunca kısa tutmak istiyorsunuz, her zaman çok az ekstra hız maliyetiyle ekstra bir koşul kullanabilir.

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

1
Ne yazık ki, yalnızca ondalık sayının solunda kabaca daha az sayıda beş veya daha fazla basamaklı sayılarla çalışır. örneğin floatToString(12345.6)döner '12345.600000000000364'. 15'i %.15fdaha düşük bir sayıya düşürmek bu örnekte çözer, ancak sayı büyüdükçe bu değerin gittikçe azaltılması gerekir. Sayının log-base-10'u temel alınarak dinamik olarak hesaplanabilir, ancak bu hızla çok karmaşık hale gelir.
JohnSpeeks

1
Bu sorunu çözmenin bir yolu, tam sayı uzunluğunu sınırlamak olabilir (yalnızca ondalık basamaktan sonraki rakamlar yerine):result = ('%15f' % val).rstrip('0').rstrip('.').lstrip(' ')
Timothy Smith

@JohnSpeeks Bunun önlenebilir olduğundan emin değilim. Sol tarafta daha fazla basamak gerekiyorsa, kayan sayıların doğruluğunu temsil edememesinin bir yan etkisidir. Söyleyebileceğim kadarıyla, bir dize olarak ortaya çıkan sayı, bir kayan nokta olarak girilen numarayla veya en azından en yakın temsiliyle aynıdır. >>>12345.600000000000364 == 12345.6 True
PolyMesh

Başka bir çözüm yazdım .
niitsuma

8

İşte benim için işe yarayan bir çözüm. Bu bir karışımıdır çözümü ile POLYMESH yeni ve kullanımı .format() sözdizimi .

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

Çıktı :

3
3
3
3.1
3.14
3.14

Bu konuda yanlış olan tek şey, mantıklı bir ondalık basamak ayarlamanız gerektiğidir. Ne kadar yüksek ayarlarsanız, o kadar kesin rakamlar temsil edebilirsiniz, ancak bunu çok yaparsanız, performansı düşürebilir.
beruic

1
Beruic'in yorumuna ek 3.141olarak .2f, sabit kodlanmış olduğu için bu daha yüksek hassasiyetli (örneğin ) şamandıralar için işe yaramaz .
TrebledJ

3

Bunu başarmak için format () yöntemini kullanabilirsiniz:

format(3.140, '.10g') burada 10 istediğiniz hassasiyettir.


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

Bunu mu demek istediniz int(a) if a % 1 else a?
beruic

Sevgili Beruic, cevabınız olumsuz cevap veriyor. a if a % 1 else int(a)doğru. Soru dize çıktı gerekiyor, Bu yüzden yeni ekledimstr
Shameem

Ah, şimdi anladım. a % 1doğrudur çünkü sıfır değildir. Bunu dolaylı ve yanlış olarak algıladım a % 1 == 0.
17'de beruic

2

Biçimlendirme büyük olasılıkla en Pythonic yol olsa da, burada more_itertools.rstriparacı kullanan alternatif bir çözüm var .

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"

Sayı, bir yüklemi tatmin eden sondaki karakterlerden arındırılmış bir dizeye dönüştürülür. İşlev tanımı fmtgerekli değildir, ancak burada geçen tüm onayları test etmek için kullanılır. Not: string girişleri üzerinde çalışır ve isteğe bağlı tahminleri kabul eder.

Ayrıca bu üçüncü taraf kitaplığıyla ilgili ayrıntılara bakın more_itertools,.


1

"3.0" olarak görünen 3. ve 3.0 ile yaşayabiliyorsanız, sıfırları float gösterimlerinden sağa soran çok basit bir yaklaşım:

print("%s"%3.140)

(istisnaları işaret ettiği için @ellimilial teşekkürler)


1
Ama print("%s"%3.0)öyle.
ellimilial

1

QuantiPhy paketini kullanmak bir seçenektir. Normalde QuantiPhy, birimler ve SI ölçek faktörleri olan sayılarla çalışırken kullanılır, ancak çeşitli güzel sayı biçimlendirme seçeneklerine sahiptir.

    >>> from quantiphy import Quantity

    >>> cases = '3 3. 3.0 3.1 3.14 3.140 3.14000'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:p}')
          3 -> 3
         3. -> 3
        3.0 -> 3
        3.1 -> 3.1
       3.14 -> 3.14
      3.140 -> 3.14
    3.14000 -> 3.14

Ve bu durumda e-notasyonu kullanmaz:

    >>> cases = '3.14e-9 3.14 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case)
    ...    print(f'{case:>7} -> {q:,p}')
    3.14e-9 -> 0
       3.14 -> 3.14
     3.14e9 -> 3,140,000,000

Tercih edebileceğiniz bir alternatif, SI birimleriyle, belki de birimlerle kullanmaktır.

    >>> cases = '3e-9 3.14e-9 3 3.14 3e9 3.14e9'.split()
    >>> for case in cases:
    ...    q = Quantity(case, 'm')
    ...    print(f'{case:>7} -> {q}')
       3e-9 -> 3 nm
    3.14e-9 -> 3.14 nm
          3 -> 3 m
       3.14 -> 3.14 m
        3e9 -> 3 Gm
     3.14e9 -> 3.14 Gm

0

OP, süper sıfırları kaldırmak ve elde edilen dizgiyi olabildiğince kısa yapmak istiyor.

% G üstel biçimlendirme çok büyük ve çok küçük değerler için ortaya çıkan dize kısaltır bulmak. Sorun, ne çok büyük ne de çok küçük olan 128.0 gibi üstel gösterime ihtiyaç duymayan değerler için gelir.

Sayıları yalnızca Decimal.normalize çok uzun olan dizeler oluşturduğunda% g üstel gösterimi kullanan kısa dizeler olarak biçimlendirmenin bir yolu. Bu en hızlı çözüm olmayabilir (Decimal.normalize kullandığından)

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

"{:.5g}".format(x)

Bunu sıfırları izlemek için şamandıraları biçimlendirmek için kullanıyorum.


3143.93 -> 3.1e + 03
j35t3r

0

İşte cevap:

import numpy

num1 = 3.1400
num2 = 3.000
numpy.format_float_positional(num1, 3, trim='-')
numpy.format_float_positional(num2, 3, trim='-')

çıkış "3.14" ve "3"

trim='-' hem arkadaki sıfırları hem de ondalıkları kaldırır.


-1

% G'yi yeterince geniş genişlikle kullanın, örneğin '% .99g'. Oldukça büyük bir sayı için sabit nokta gösteriminde yazdırılır.

EDIT: çalışmıyor

>>> '%.99g' % 0.0000001
'9.99999999999999954748111825886258685613938723690807819366455078125e-08'

1
.99genişlik değil hassastır; biraz kullanışlı ama gerçek hassasiyeti bu şekilde ayarlayamazsınız (kendiniz kesmek dışında).
Kos

-1

Bunun gibi kullanabilirsiniz max():

print(max(int(x), x))


1
xOlumsuz olan durumu düşünmelisiniz . if x < 0: print(min(x), x) else : print(max(x), x)
ThunderPhoenix

Json stringify yapmak istediğinizde yararlı bir yöntem. float 1.0 int 1 olarak değişir, bu yüzden javascript ile aynı şekilde çalışır.
pingze

-3

Bunu en pitonik bir şekilde şöyle yapabilirsiniz:

python3:

"{:0.0f}".format(num)

Haklısın. En kolay yol "{: g}" biçimini kullanmaktır. (Num)
Pyglouthon

-4

% F ile başa çıkmak ve

% .2f

, burada: .2f == .00 yüzer.

Misal:

print "Fiyat:% .2f"% fiyatlar [ürün]

çıktı:

Fiyat: 1.50


1
Bu sorunun ne istediğini açıkça belirtmiyor. İndirmek gerekiyor.
1919'da
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.