Python'da bir sayı önemli rakamlara nasıl yuvarlanır


159

Bir kullanıcı arayüzünde görüntülenmek için bir kayan noktayı yuvarlamam gerekiyor. Örneğin, önemli bir rakama göre:

1234 -> 1000

0.12 -> 0.1

0,012 -> 0,01

0,062 -> 0,06

6253 -> 6000

1999 -> 2000

Python kitaplığını kullanarak bunu yapmanın güzel bir yolu var mı yoksa kendim mi yazmalıyım?


2
Sadece çıktıyı mı biçimlendiriyorsunuz? Bunu mu soruyorsun? docs.python.org/library/stdtypes.html#string-formatting mi yoksa bu mu? docs.python.org/library/string.html#string-formatting
S.Lott

0.062 ve 6253 için hangi çıktıyı bekliyorsunuz?
lamirap

Hassas paket şimdi bunu yapıyor. Benim yayınlanmıştır cevap bu geçerlidir nasıl ayrıntıları.
William Rusnack

@Falken tarafından verilen cevap, istenen doğru olan sonuçları verir. Neredeyse diğerleri 1000.0, sondaki ondalık basamaklar ve / veya sıfırlar gibi sonuçlar verir ; bu, standart uygulamada çok daha fazla kesinliği gösterir.
nealmcb

Yanıtlar:


150

Tam sayıları yuvarlamak için negatif sayılar kullanabilirsiniz:

>>> round(1234, -3)
1000.0

Bu nedenle, yalnızca en önemli basamağa ihtiyacınız varsa:

>>> from math import log10, floor
>>> def round_to_1(x):
...   return round(x, -int(floor(log10(abs(x)))))
... 
>>> round_to_1(0.0232)
0.02
>>> round_to_1(1234243)
1000000.0
>>> round_to_1(13)
10.0
>>> round_to_1(4)
4.0
>>> round_to_1(19)
20.0

1'den büyükse, muhtemelen float'ı tam sayıya çevirmek zorunda kalacaksınız.


3
Doğru çözüm budur. Kullanılması log10o yuvarlak nasıl belirlemek için tek doğru yoldur.
Wolph

75
round_to_n = lambda x, n: Yuvarlak (x, -INT (kat (log 10 (x))) + (n - 1))
Roy Hyunjin Han

29
Kullanmalısınız log10(abs(x)), aksi takdirde negatif sayılar başarısız olur (Ve x == 0elbette ayrı ayrı ele alın)
Tobias Kienzler

2
Bunu şimdi yapan ve muhtemelen bundan daha kolay ve daha sağlam olan bir paket oluşturdum. Mesaj Bağlantısı , Repo Bağlantısı . Bu yardımcı olur umarım!
William Rusnack

3
round_to_n = lambda x, n: x if x == 0 else round(x, -int(math.floor(math.log10(abs(x)))) + (n - 1))karşı korur x==0ve x<0teşekkür ederim @ RoyHyunjinHan ve @TobiasKienzler. Math.inf gibi tanımlanmamış veya None vb. Çöplere karşı koruma sağlamaz
AJP

102

Dize biçimlendirmesindeki% g, bir dizi anlamlı rakama yuvarlanmış bir kayan noktayı biçimlendirir. Bazen 'e' bilimsel gösterimi kullanır, bu nedenle yuvarlatılmış dizeyi tekrar bir kayan sayıya ve ardından% s dizge biçimlendirmesine dönüştürün.

>>> '%s' % float('%.1g' % 1234)
'1000'
>>> '%s' % float('%.1g' % 0.12)
'0.1'
>>> '%s' % float('%.1g' % 0.012)
'0.01'
>>> '%s' % float('%.1g' % 0.062)
'0.06'
>>> '%s' % float('%.1g' % 6253)
'6000.0'
>>> '%s' % float('%.1g' % 1999)
'2000.0'

9
OP'nin gerekliliği 1999 için '2000.0' olarak değil '2000' olarak biçimlendirilmesiydi. Bunu başarmak için yönteminizi değiştirmenin önemsiz bir yolunu göremiyorum.
Tim Martin

1
Hep istediğim buydu! bunu nerede buldun
djhaskin987

13
% G davranışının her zaman doğru olmadığını unutmayın. Özellikle , önemli olsalar bile her zaman sondaki sıfırları kırpar. 1.23400 sayısının 6 anlamlı basamağı vardır, ancak "% .6g"% (1.23400) yanlış olan "1.234" ile sonuçlanacaktır. Bu blog gönderisinde daha fazla ayrıntı: randlet.com/blog/python-significant-figures-format
randlet

3
Sadece Evgeny yanıtında yöntemi gibi, bu doğru yuvarlak başarısız 0.075etmek 0.08. Onun 0.07yerine geri döner .
Gabriel

1
round_sig = lambda f,p: float(('%.' + str(p) + 'e') % f)önemli basamakların sayısını ayarlamanıza olanak tanır!
denizb

55

1'den farklı ondalık sayıya sahip olmak istiyorsanız (aksi takdirde Evgeny ile aynıdır):

>>> from math import log10, floor
>>> def round_sig(x, sig=2):
...   return round(x, sig-int(floor(log10(abs(x))))-1)
... 
>>> round_sig(0.0232)
0.023
>>> round_sig(0.0232, 1)
0.02
>>> round_sig(1234243, 3)
1230000.0

8
round_sig (-0.0232) -> matematik alan hatası, oraya bir abs () eklemek isteyebilirsiniz;)
dgorissen

2
Sadece Evgeny en ve Peter Graham yanıtlar yöntemleri gibi, bu doğru yuvarlak başarısız 0.075etmek 0.08. Onun 0.07yerine geri döner .
Gabriel

3
Ayrıca round_sig (0) için başarısız olur.
Yuval Atzmon

2
@Gabriel Bu, bilgisayarınızda çalışan yerleşik bir python "özelliğidir" ve işlevin davranışında kendini gösterir round. docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues
Acemi C

1
@Gabriel "0.075" yuvarlamasından neden 0.7 geri almayı beklemeniz gerektiğini açıklayan bir yanıt ekledim ! bkz. stackoverflow.com/a/56974893/1358308
Sam Mason

33
f'{float(f"{i:.1g}"):g}'
# Or with Python <3.6,
'{:g}'.format(float('{:.1g}'.format(i)))

Bu çözüm diğerlerinin hepsinden farklıdır çünkü:

  1. o tam olarak OP soru çözer
  2. o mu değil herhangi gerek ekstra paket
  3. Bu etmez olmayan herhangi bir kullanıcı tarafından ihtiyaç yardımcı fonksiyon veya bir matematik işlemi

Rasgele sayıda nanlamlı rakamlar için şunları kullanabilirsiniz:

print('{:g}'.format(float('{:.{p}g}'.format(i, p=n))))

Ölçek:

a = [1234, 0.12, 0.012, 0.062, 6253, 1999, -3.14, 0., -48.01, 0.75]
b = ['{:g}'.format(float('{:.1g}'.format(i))) for i in a]
# b == ['1000', '0.1', '0.01', '0.06', '6000', '2000', '-3', '0', '-50', '0.8']

Not : Bu çözümle, anlamlı rakamların sayısını girdiden dinamik olarak uyarlamak mümkün değildir, çünkü farklı sayılarda takip eden sıfırları ( 3.14 == 3.1400) olan sayıları ayırt etmenin standart bir yolu yoktur . Bunu yapmanız gerekiyorsa, hassas pakette sağlananlar gibi standart dışı işlevlere ihtiyaç vardır.


1
Bilginize: Kodumdan birinde aynı sorunu çözmeye çalışırken bu çözümü eddygeek'ten bağımsız olarak buldum. Şimdi, benim çözümümün onunkiyle neredeyse aynı olduğunu anlıyorum (sadece hatalı çıktıyı fark ettim ve kodu okuma zahmetine girmedim, benim hatam). Muhtemelen cevabının altındaki kısa bir yorum yeni bir cevap yerine yeterli olurdu ... Tek (anahtar) fark, :gtam sayıları koruyan formatlayıcının iki kez kullanılmasıdır .
Falken

2
Vay canına, cevabınızın gerçekten yukarıdan aşağıya doğru okunması gerekiyor;) Bu çift atış hilesi kirli, ama düzgün. (1999'un 5 anlamlı basamağı 2000.0 önerdiği gibi biçimlendirildiğine dikkat edin , bu yüzden {:g}tekrar geçmesi gerekir .) Genel olarak, bazı teknikler (son anlamlıın üstündeki üst çizgi gibi) kullanılmadıkça, genel olarak, sonunda sıfır olan tam sayılar, anlamlı rakamlar açısından belirsizdir.
Tomasz Gandor

Bunun nasıl çalıştığını bana anlatır mısın? Ne var :.1gve :gben de daha önce karşılaştığımı sanmıyorum ve belgelerde de bir şey bulamadım
EA

@EA doc bir açıklaması var burada için g. İlk biçimlendirme {:.1g}bir önemli basamak tutar, ancak bir kayan nokta sağlarsanız tam olarak tatmin edici değildir, çünkü buna benzer bir şey elde edebilirsiniz 1000.0. İkincisi {:g}, ondalık noktadan sonra yalnızca 0 olan bir kayan noktanın tamsayı ( 1000) olmasını sağlar.
Falken

Üzgünüm, önceki yorumum pek kapsamlı değildi, tekrar deneyelim: {:.1g}önemli bir rakam tutar ama üslü gösterimde bir sayı döndürebilir. Bundan kaçınmak için float () kullanıyoruz. Ama sonra 1000.0, önemli bir rakamı olan bir sayı için doğru gösterim olmadığını anlıyoruz . Bunun yerine istiyoruz 1000. Bunu sağlamak için başka bir tane kullanıyoruz {:g}. Dokümana göre: 'Ondalık nokta, arkasından kalan basamak yoksa da kaldırılır'. Bu cevabı yazdığımda bu bölümün dokümandan eksik olduğuna eminim, bunu nasıl bulduğumdan emin değilim, çok uzun zaman önceydi! ;-)
Falken

10

İstediğinizi yapan hassas bir şekilde paket oluşturdum . Rakamlarınızı az ya da çok anlamlı rakamlar vermenizi sağlar.

Aynı zamanda, belirli sayıda anlamlı rakamlarla standart, bilimsel ve mühendislik gösterimi sağlar.

Kabul edilen cevapta satır var

>>> round_to_1(1234243)
1000000.0

Bu aslında 8 sig incir olduğunu belirtir. 1234243 sayısı için kitaplığım yalnızca bir önemli rakam gösteriyor:

>>> from to_precision import to_precision
>>> to_precision(1234243, 1, 'std')
'1000000'
>>> to_precision(1234243, 1, 'sci')
'1e6'
>>> to_precision(1234243, 1, 'eng')
'1e6'

Ayrıca son önemli rakamı yuvarlar ve bir gösterim belirtilmezse hangi gösterimin kullanılacağını otomatik olarak seçebilir:

>>> to_precision(599, 2)
'600'
>>> to_precision(1164, 2)
'1.2e3'

Şimdi aynısını arıyorum ama bir
Pandas df'ye

@mhoff muhtemelen bir lambda ile pandalar haritasını kullanabilirsiniz. lambda x: to_precision(x, 2)
William Rusnack

Bunu (PyPI) [ pypi.org/] sitesine ekleyin . Anladığım kadarıyla orada böyle bir şey yok.
Morgoth

bu harika bir paket ama bence özelliklerin çoğu artık sigfig modülünde
HyperActive

1
bir hatası var: std_notation (9.999999999999999e-05, 3) şunu verir: '0.00010' bu sadece 2 önemli basamaktır
Boris Mulder

6

Soruyu doğrudan yanıtlamak için, işte R işlevinden adlandırma kullanan sürümüm :

import math

def signif(x, digits=6):
    if x == 0 or not math.isfinite(x):
        return x
    digits -= math.ceil(math.log10(abs(x)))
    return round(x, digits)

Bu yanıtı göndermemdeki ana nedenim, "0.075" in 0.08 yerine 0.07'ye yuvarlandığından şikayet eden yorumlardır. Bunun nedeni, "Acemi C" tarafından belirtildiği gibi, hem sonlu kesinliğe hem de bir taban-2 gösterimine sahip kayan nokta aritmetiğinin bir kombinasyonudur . Gerçekte temsil edilebilecek 0,075'e en yakın sayı biraz daha küçüktür, bu nedenle yuvarlama, safça beklediğinizden farklı bir şekilde ortaya çıkar.

Ayrıca, bunun ondalık olmayan kayan nokta aritmetiğinin herhangi bir kullanımı için geçerli olduğuna dikkat edin, örneğin C ve Java'nın her ikisinde de aynı sorun vardır.

Daha ayrıntılı göstermek için Python'dan sayıyı "onaltılık" biçiminde biçimlendirmesini istiyoruz:

0.075.hex()

bize hangi veriyor: 0x1.3333333333333p-4. Bunu yapmanın nedeni, normal ondalık gösterimin genellikle yuvarlamayı içermesi ve dolayısıyla bilgisayarın sayıyı gerçekte nasıl "gördüğü" değildir. Bu biçime alışkın değilseniz, birkaç yararlı referans Python belgeleri ve C standardıdır .

Bu sayıların nasıl çalıştığını biraz göstermek için, şunu yaparak başlangıç ​​noktamıza geri dönebiliriz:

0x13333333333333 / 16**13 * 2**-4

hangi çıktı almalıdır 0.075. 16**13ondalık noktadan sonra 13 onaltılık hane 2**-4olması ve onaltılık üslerin taban-2 olmasıdır.

Şimdi kayan değerlerin nasıl temsil edildiğine dair bir fikrimiz var, decimalmodülü bize biraz daha kesinlik vermek için kullanabiliriz ve bize neler olduğunu gösterebiliriz:

from decimal import Decimal

Decimal(0x13333333333333) / 16**13 / 2**4

vermek: 0.07499999999999999722444243844ve umarım neden round(0.075, 2)değerlendirildiğini açıklamak0.07


2
Bu, kod düzeyinde 0.075'in neden 0.07'ye yuvarlandığının harika bir açıklamasıdır , ancak bize (fizik bilimlerinde) aşağıya değil her zaman yuvarlamamız öğretildi. Dolayısıyla beklenen davranış, sonuç olarak 0,08'e sahip olmaktır, buna rağmen kayan nokta hassasiyeti sorunları.
Gabriel

1
Karışıklığın nerede olduğundan emin değilim: 0,075 girdiğinizde aslında ~ 0,07499 (yukarıdaki gibi) giriyorsunuz, bu da normal matematik kurallarına göre yuvarlanıyor. 0,075'i temsil edebilecek bir veri türü ( ondalık kayan nokta gibi ) kullanıyorsanız, bu gerçekten 0,08'e yuvarlanmalıdır
Sam Mason

1
Kafam karışık değil. 0.075 girdiğimde aslında 0.075 giriyorum. Kodun içindeki kayan nokta matematiğinde ne olursa olsun umurumda değil.
Gabriel

@Gabriel: Eğer olursa etmişti kasten girilmiş 0.074999999999999999, ne bu durumda almak için beklenebilir?
Mark Dickinson

1
@MarkDickinson buna bağlıdır. Bir önemli rakam: 0,07, iki: 0,075.
Gabriel

5

Bir tamsayıyı 1 anlamlı rakama yuvarlamak için temel fikir, onu noktadan önce 1 basamak olan bir kayan noktaya dönüştürmek ve onu yuvarlamak, ardından orijinal tamsayı boyutuna geri dönüştürmektir.

Bunu yapmak için, tamsayıdan 10'un en büyük kuvvetini bilmemiz gerekir. Bunun için log 10 fonksiyonunun floor'unu kullanabiliriz.

from math import log10, floor
def round_int(i,places):
    if i == 0:
        return 0
    isign = i/abs(i)
    i = abs(i)
    if i < 1:
        return 0
    max10exp = floor(log10(i))
    if max10exp+1 < places:
        return i
    sig10pow = 10**(max10exp-places+1)
    floated = i*1.0/sig10pow
    defloated = round(floated)*sig10pow
    return int(defloated*isign)

1
Artı python yuvarlak (.., rakamlar) olmadan ve herhangi bir dizge eklenmeden çalışan çözüm için bir tane!
Steve Rogers

4
def round_to_n(x, n):
    if not x: return 0
    power = -int(math.floor(math.log10(abs(x)))) + (n - 1)
    factor = (10 ** power)
    return round(x * factor) / factor

round_to_n(0.075, 1)      # 0.08
round_to_n(0, 1)          # 0
round_to_n(-1e15 - 1, 16) # 1000000000000001.0

Umarım yukarıdaki tüm cevapların en iyisini alırsınız (eksi onu bir satır lambda olarak koyabilmek;)). Henüz araştırılmadım, bu yanıtı düzenlemekten çekinmeyin:

round_to_n(1e15 + 1, 11)  # 999999999999999.9

4

Negatif sayıları ve küçük sayıları (sıfır dahil) işlemek için indgar'ın çözümünü değiştirdim.

from math import log10, floor
def round_sig(x, sig=6, small_value=1.0e-9):
    return round(x, sig - int(floor(log10(max(abs(x), abs(small_value))))) - 1)

Neden sadece test etmiyorsunuz x == 0? Tek astarlı birini seviyorsanız, sadece return 0 if x==0 else round(...).
pjvandehaar

2
@pjvandehaar, genel durum için haklısın ve bunu da eklemeliydim. Ayrıca yapmam gereken sayısal hesaplamalar için ara sıra 1e-15 gibi rakamlar alıyoruz. Uygulamamızda, iki küçük sayının (bunlardan biri sıfır olabilir) eşit kabul edilmesini istiyoruz. Ayrıca bazı insanlar küçük sayıları (1e-9, 1e-15 veya hatta 1e-300 olabilir) sıfıra yuvarlamak ister.
ryan281

1
İlginç. Bunu açıkladığınız için teşekkürler. Bu durumda, bu çözümü gerçekten seviyorum.
pjvandehaar

@Morgoth Bu ilginç ve zor bir problem. Sizin de belirttiğiniz gibi, basılı değer 3 önemli basamağı göstermiyor, ancak değer doğrudur (örneğin 0.970 == 0.97). f'{round_sig(0.9701, sig=3):0.3f}'Sıfırın basılmasını istiyorsanız, diğer baskı çözümlerinden bazılarını kullanabileceğinizi düşünüyorum .
ryan281

3

Dizeleri dahil etmeden yuvarlamak istiyorsanız, yukarıdaki yorumlarda gömülü bulduğum bağlantı:

http://code.activestate.com/lists/python-tutor/70739/

beni en iyi şekilde etkiliyor. Daha sonra herhangi bir dize biçimlendirme tanımlayıcısı ile yazdırdığınızda, makul bir çıktı elde edersiniz ve sayısal gösterimi diğer hesaplama amaçları için kullanabilirsiniz.

Bağlantıdaki kod üç satırlıdır: def, doc ve return. Bir hatası var: patlayan logaritmaları kontrol etmeniz gerekiyor. O kolay. Girişi ile karşılaştırın sys.float_info.min. Tam çözüm şudur:

import sys,math

def tidy(x, n):
"""Return 'x' rounded to 'n' significant digits."""
y=abs(x)
if y <= sys.float_info.min: return 0.0
return round( x, int( n-math.ceil(math.log10(y)) ) )

Herhangi bir skaler sayısal değer için çalışır ve herhangi bir floatnedenle yanıtı kaydırmanız gerekirse n, a olabilir. Aslında sınırı şu şekilde zorlayabilirsiniz:

sys.float_info.min*sys.float_info.epsilon

bir hata yapmadan, herhangi bir nedenle minik değerlerle çalışıyorsanız.


2

Bunu kutudan çıkarabilecek bir şey düşünemiyorum. Ancak kayan nokta sayıları için oldukça iyi işlenir.

>>> round(1.2322, 2)
1.23

Tam sayılar daha yanıltıcıdır. Hafızada temel 10 olarak depolanmazlar, bu yüzden önemli yerler yapılacak doğal bir şey değildir. Gerçi bir dizge olduklarında uygulamak oldukça önemsizdir.

Veya tamsayılar için:

>>> def intround(n, sigfigs):
...   n = str(n)
...   return n[:sigfigs] + ('0' * (len(n)-(sigfigs)))

>>> intround(1234, 1)
'1000'
>>> intround(1234, 2)

Herhangi bir sayıyı işleyen bir işlev oluşturmak istiyorsanız, tercihim ikisini de dizelere dönüştürmek ve ne yapılacağına karar vermek için ondalık bir basamak aramak olacaktır:

>>> def roundall1(n, sigfigs):
...   n = str(n)
...   try:
...     sigfigs = n.index('.')
...   except ValueError:
...     pass
...   return intround(n, sigfigs)

Diğer bir seçenek de türü kontrol etmektir. Bu çok daha az esnek olacak ve muhtemelen Decimalnesneler gibi diğer sayılarla iyi oynamayacaktır :

>>> def roundall2(n, sigfigs):
...   if type(n) is int: return intround(n, sigfigs)
...   else: return round(n, sigfigs)

Sadece dizelerle uğraşmak sayıları yuvarlamaz. 1999 1 önemli rakama yuvarlanır 2000 değil 1000 olduğunu
Peter Graham


2

Gönderilen cevap, verildiğinde mevcut olan en iyisiydi, ancak bazı sınırlamaları var ve teknik olarak doğru anlamlı rakamlar üretmiyor.

numpy.format_float_positional , istenen davranışı doğrudan destekler. Aşağıdaki parça x, bilimsel gösterim gizlenmiş olarak 4 anlamlı rakama biçimlendirilmiş kayan değeri döndürür .

import numpy as np
x=12345.6
np.format_float_positional(x, precision=4, unique=False, fractional=False, trim='k')
> 12340.

Belgeler ( numpy.org/doc/stable/reference/generated/… adresine taşınmıştır ), bu işlevin Dragon4 algoritmasını (Steele & White 1990, dl.acm.org/doi/pdf/10.1145/93542.93559 ) uyguladığını belirtir . Can sıkıcı sonuçlar üretir, örn print(*[''.join([np.format_float_positional(.01*a*n,precision=2,unique=False,fractional=False,trim='k',pad_right=5) for a in [.99, .999, 1.001]]) for n in [8,9,10,11,12,19,20,21]],sep='\n'). Dragon4'ün kendisini kontrol etmedim.
Rainald62

0

Bununla da karşılaştım ama yuvarlama türü üzerinde kontrole ihtiyacım vardı. Bu nedenle, değeri, yuvarlama türünü ve istenen önemli basamakları dikkate alabilen hızlı bir işlev (aşağıdaki koda bakın) yazdım.

import decimal
from math import log10, floor

def myrounding(value , roundstyle='ROUND_HALF_UP',sig = 3):
    roundstyles = [ 'ROUND_05UP','ROUND_DOWN','ROUND_HALF_DOWN','ROUND_HALF_UP','ROUND_CEILING','ROUND_FLOOR','ROUND_HALF_EVEN','ROUND_UP']

    power =  -1 * floor(log10(abs(value)))
    value = '{0:f}'.format(value) #format value to string to prevent float conversion issues
    divided = Decimal(value) * (Decimal('10.0')**power) 
    roundto = Decimal('10.0')**(-sig+1)
    if roundstyle not in roundstyles:
        print('roundstyle must be in list:', roundstyles) ## Could thrown an exception here if you want.
    return_val = decimal.Decimal(divided).quantize(roundto,rounding=roundstyle)*(decimal.Decimal(10.0)**-power)
    nozero = ('{0:f}'.format(return_val)).rstrip('0').rstrip('.') # strips out trailing 0 and .
    return decimal.Decimal(nozero)


for x in list(map(float, '-1.234 1.2345 0.03 -90.25 90.34543 9123.3 111'.split())):
    print (x, 'rounded UP: ',myrounding(x,'ROUND_UP',3))
    print (x, 'rounded normal: ',myrounding(x,sig=3))

0

Python 2.6+ yeni stil biçimlendirmesini kullanma (% -style kullanımdan kaldırıldığı için):

>>> "{0}".format(float("{0:.1g}".format(1216)))
'1000.0'
>>> "{0}".format(float("{0:.1g}".format(0.00356)))
'0.004'

Python 2.7+ sürümünde baştaki ’ 0leri atlayabilirsiniz .


Python'un hangi sürümüyle? Python 3.6.3 | Anaconda, Inc. | (varsayılan, 13 Ekim 2017, 12:02:49) aynı eski yuvarlama sorununa sahiptir. "{0}". Format (float ("{0: .1g}". Format (0.075))) "0.08" değil "0.07" sonucunu verir
Don Mclachlan

@DonMclachlan Bunun neden beklendiğine ilişkin bir açıklama ekledim stackoverflow.com/a/56974893/1358308
Sam Mason

0

Bu işlev, sayı 10'dan ** (- ondalık_konumlar) büyükse normal bir yuvarlama yapar, aksi takdirde anlamlı ondalık konumların sayısına ulaşılıncaya kadar daha fazla ondalık ekler:

def smart_round(x, decimal_positions):
    dp = - int(math.log10(abs(x))) if x != 0.0 else int(0)
    return round(float(x), decimal_positions + dp if dp > 0 else decimal_positions)

Umarım yardımcı olur.


0

https://stackoverflow.com/users/1391441/gabriel , aşağıdakiler rnd (.075, 1) ile ilgili endişenizi gideriyor mu? Uyarı: değeri bir kayan nokta olarak döndürür

def round_to_n(x, n):
    fmt = '{:1.' + str(n) + 'e}'    # gives 1.n figures
    p = fmt.format(x).split('e')    # get mantissa and exponent
                                    # round "extra" figure off mantissa
    p[0] = str(round(float(p[0]) * 10**(n-1)) / 10**(n-1))
    return float(p[0] + 'e' + p[1]) # convert str to float

>>> round_to_n(750, 2)
750.0
>>> round_to_n(750, 1)
800.0
>>> round_to_n(.0750, 2)
0.075
>>> round_to_n(.0750, 1)
0.08
>>> math.pi
3.141592653589793
>>> round_to_n(math.pi, 7)
3.141593

0

Bu bir dize döndürür, böylece kesirli parçalar olmadan sonuçlar ve aksi takdirde E gösteriminde görünecek küçük değerler doğru şekilde gösterilir:

def sigfig(x, num_sigfig):
    num_decplace = num_sigfig - int(math.floor(math.log10(abs(x)))) - 1
    return '%.*f' % (num_decplace, round(x, num_decplace))

0

Bu kadar kapsamlı bir şekilde cevaplanan bir soru göz önüne alındığında, neden başka bir tane eklemiyorsunuz?

Bu benim estetiğime biraz daha iyi uyuyor, ancak yukarıdakilerin çoğu karşılaştırılabilir.

import numpy as np

number=-456.789
significantFigures=4

roundingFactor=significantFigures - int(np.floor(np.log10(np.abs(number)))) - 1
rounded=np.round(number, roundingFactor)

string=rounded.astype(str)

print(string)

Bu, tek tek sayılar ve uyuşuk diziler için çalışır ve negatif sayılar için iyi çalışmalıdır.

Ekleyebileceğimiz ek bir adım daha var - np.round (), yuvarlanmış bir tamsayı olsa bile ondalık bir sayı döndürür (yani, anlamlıFigures = 2 için -460 geri almayı bekleyebiliriz ancak bunun yerine -460.0 elde ederiz). Bunu düzeltmek için bu adımı ekleyebiliriz:

if roundingFactor<=0:
    rounded=rounded.astype(int)

Ne yazık ki, bu son adım bir dizi sayı için işe yaramayacak - ihtiyacınız olup olmadığını anlamak için bunu sevgili okuyucuya bırakacağım.


0

Sigfig paket / kütüphane kapakları bu. Kurduktan sonra şunları yapabilirsiniz:

>>> from sigfig import round
>>> round(1234, 1)
1000
>>> round(0.12, 1)
0.1
>>> round(0.012, 1)
0.01
>>> round(0.062, 1)
0.06
>>> round(6253, 1)
6000
>>> round(1999, 1)
2000

0
import math

  def sig_dig(x, n_sig_dig):
      num_of_digits = len(str(x).replace(".", ""))
      if n_sig_dig >= num_of_digits:
          return x
      n = math.floor(math.log10(x) + 1 - n_sig_dig)
      result = round(10 ** -n * x) * 10 ** n
      return float(str(result)[: n_sig_dig + 1])


    >>> sig_dig(1234243, 3)
    >>> sig_dig(243.3576, 5)

        1230.0
        243.36

Bu işlev yapması gerekeni yapmıyor. sig_dig(1234243, 3)olmalı 1230000ve olmamalı 1230.0.
timmey

Sadece sonucu döndürürseniz, o zaman iyi olur (yani işlevinizin son satırını kaldırın).
timmey

Ayrıca, math.log10(abs(x))negatif sayılarla başa çıkmak için mutlak değeri almalısınız . İki düzeltme göz önüne alındığında, iyi çalışıyor gibi görünüyor ve oldukça hızlı.
timmey
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.