Cara membulatkan angka ke angka signifikan dengan Python

148

Saya perlu membulatkan float untuk ditampilkan di UI. Misalnya, untuk satu tokoh penting:

1234 -> 1000

0,12 -> 0,1

0,012 -> 0,01

0,062 -> 0,06

6253 -> 6000

1999 -> 2000

Apakah ada cara yang bagus untuk melakukan ini menggunakan perpustakaan Python, atau apakah saya harus menulisnya sendiri?

Peter Graham
sumber
2
Apakah Anda hanya memformat output? Apakah Anda bertanya tentang ini? docs.python.org/library/stdtypes.html#string-formatting atau ini? docs.python.org/library/string.html#string-formatting
S.Lott
output apa yang Anda harapkan untuk 0,062 dan 6253?
lamirap
Paket ke presisi sekarang melakukan ini. Jawaban saya yang diposting menjelaskan bagaimana ini berlaku.
William Rusnack

Jawaban:

146

Anda dapat menggunakan angka negatif untuk membulatkan bilangan bulat:

>>> round(1234, -3)
1000.0

Jadi, jika Anda hanya membutuhkan digit paling signifikan:

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

Anda mungkin harus berhati-hati mengubah float ke integer jika lebih besar dari 1.

Evgeny
sumber
3
Ini solusi yang tepat. Menggunakan log10adalah satu-satunya cara yang tepat untuk menentukan cara membulatkannya.
Wolph
73
round_to_n = lambda x, n: round (x, -int (floor (log10 (x))) + (n - 1))
Roy Hyunjin Han
28
Anda harus menggunakan log10(abs(x)), jika tidak, angka negatif akan gagal (Dan memperlakukan x == 0secara terpisah tentu saja)
Tobias Kienzler
2
Saya telah membuat paket yang melakukan ini sekarang dan mungkin lebih mudah dan lebih kuat dari yang ini. Tautan Posting , Tautan Repo . Semoga ini membantu!
William Rusnack
2
round_to_n = lambda x, n: x if x == 0 else round(x, -int(math.floor(math.log10(abs(x)))) + (n - 1))melindungi x==0dan x<0Terima kasih @RoyHyunjinHan dan @TobiasKienzler. Tidak dilindungi terhadap undefined seperti math.inf, atau sampah seperti Tidak ada dll
AJP
98

% g dalam pemformatan string akan memformat float dibulatkan ke beberapa angka penting. Terkadang akan menggunakan notasi ilmiah 'e', ​​jadi konversikan string bulat kembali ke float lalu melalui pemformatan string% s.

>>> '%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'
Peter Graham
sumber
7
Persyaratan OP adalah agar tahun 1999 diformat sebagai '2000', bukan sebagai '2000.0'. Saya tidak bisa melihat cara sepele untuk mengubah metode Anda untuk mencapai ini.
Tim Martin
1
Itulah yang selalu saya inginkan! dimana kamu menemukan ini?
djhaskin987
12
Perhatikan bahwa perilaku% g tidak selalu benar. Khususnya itu selalu memotong angka nol bahkan jika mereka signifikan. Angka 1.23400 memiliki 6 digit signifikan, tetapi "% .6g"% (1.23400) akan menghasilkan "1.234" yang tidak benar. Lebih detail dalam posting blog ini: randlet.com/blog/python-significant-figures-format
randlet
3
Sama seperti metode dalam jawaban Evgeny ini, ini gagal untuk benar bulat 0.075untuk 0.08. Ia mengembalikannya 0.07.
Gabriel
1
round_sig = lambda f,p: float(('%.' + str(p) + 'e') % f)memungkinkan Anda untuk menyesuaikan jumlah digit signifikan!
denizb
49

Jika Anda ingin memiliki selain 1 desimal yang signifikan (jika tidak sama dengan Evgeny):

>>> 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
indgar
sumber
8
round_sig (-0.0232) -> kesalahan domain matematika, Anda mungkin ingin menambahkan abs () di sana;)
dgorissen
2
Sama seperti metode dalam jawaban Evgeny dan Peter Graham, ini gagal untuk benar bulat 0.075untuk 0.08. Ia mengembalikannya 0.07.
Gabriel
3
Juga gagal untuk round_sig (0).
Yuval Atzmon
2
@Gabriel Itu adalah "fitur" built-in python yang berjalan di komputer Anda, dan memanifestasikan dirinya dalam perilaku fungsinya round. docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues
Novice C
1
@Gabriel Saya telah menambahkan jawaban yang menjelaskan mengapa Anda harus berharap mendapatkan 0,7 kembali dari pembulatan "0,075"! lihat stackoverflow.com/a/56974893/1358308
Sam Mason
30
f'{float(f"{i:.1g}"):g}'
# Or with Python <3.6,
'{:g}'.format(float('{:.1g}'.format(i)))

Solusi ini berbeda dari yang lain karena:

  1. itu persis memecahkan pertanyaan OP
  2. itu tidak memerlukan paket tambahan
  3. itu tidak memerlukan user-defined fungsi tambahan atau operasi matematika

Untuk angka nsignifikan yang sewenang-wenang , Anda dapat menggunakan:

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

Uji:

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']

Catatan : dengan solusi ini, tidak mungkin untuk mengadaptasi jumlah angka signifikan secara dinamis dari input karena tidak ada cara standar untuk membedakan angka dengan angka trailing zero yang berbeda ( 3.14 == 3.1400). Jika Anda perlu melakukannya, maka fungsi-fungsi non-standar seperti yang disediakan dalam paket to-precision diperlukan.

Falken
sumber
FYI: Saya menemukan solusi ini secara independen dari eddygeek ketika saya mencoba untuk memecahkan masalah yang sama di salah satu kode saya. Sekarang saya menyadari bahwa solusi saya, jelas, hampir identik dengan miliknya (saya hanya melihat output yang salah dan tidak repot-repot membaca kode, kesalahan saya). Mungkin komentar singkat di bawah jawabannya sudah cukup alih-alih jawaban baru ... Satu-satunya (kunci) perbedaan adalah penggunaan ganda :gformatter yang mempertahankan bilangan bulat.
Falken
Wow, jawaban Anda harus benar-benar dibaca dari atas ke bawah;) Trik pemain ganda ini kotor, tetapi rapi. (Perhatikan bahwa 1999 diformat sebagai 2000.0 menyarankan 5 digit signifikan, sehingga harus melalui {:g}lagi.) Secara umum, bilangan bulat dengan nol trailing adalah ambigu berkaitan dengan angka signifikan, kecuali beberapa teknik (seperti overline di atas signifikan terakhir) digunakan.
Tomasz Gandor
8

Saya telah membuat paket dengan presisi yang melakukan apa yang Anda inginkan. Ini memungkinkan Anda untuk memberikan angka Anda angka yang lebih atau kurang signifikan.

Ini juga menghasilkan notasi standar, ilmiah, dan teknik dengan sejumlah angka penting yang ditentukan.

Dalam jawaban yang diterima ada garis

>>> round_to_1(1234243)
1000000.0

Itu sebenarnya menentukan 8 buah ara. Untuk angka 1234243 perpustakaan saya hanya menampilkan satu angka penting:

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

Itu juga akan membulatkan angka signifikan terakhir dan secara otomatis dapat memilih notasi apa yang akan digunakan jika notasi tidak ditentukan:

>>> to_precision(599, 2)
'600'
>>> to_precision(1164, 2)
'1.2e3'
William Rusnack
sumber
Sekarang saya mencari yang sama tetapi diterapkan pada panda df
mhoff
@mhoff Anda mungkin dapat menggunakan peta panda dengan lambda. lambda x: to_precision(x, 2)
William Rusnack
Tambahkan ini ke (PyPI) [ pypi.org/] . Tidak ada yang seperti ini yang ada di sana, sejauh yang saya tahu.
Morgoth
ini adalah paket besar tapi saya pikir sebagian besar fitur sekarang di modul sigfig
hiperaktif
1
ia memiliki bug: std_notation (9.9999999999999999e-05, 3) memberikan: '0,00010' yang hanya 2 angka signifikan
Boris Mulder
5

Untuk membulatkan bilangan bulat ke 1 angka penting, ide dasarnya adalah mengonversinya menjadi titik mengambang dengan 1 digit sebelum titik dan membulatkannya, lalu mengonversinya kembali ke ukuran bilangan bulat aslinya.

Untuk melakukan ini kita perlu mengetahui kekuatan terbesar 10 lebih kecil dari integer. Kita dapat menggunakan lantai fungsi log 10 untuk ini.

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)
Cris Stringfellow
sumber
1
Ditambah satu untuk solusi yang berfungsi tanpa putaran python (..., digit) dan tanpa ikatan!
Steve Rogers
5

Untuk langsung menjawab pertanyaan, inilah versi saya menggunakan penamaan dari fungsi R :

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)

Alasan utama saya untuk memposting jawaban ini adalah komentar yang mengeluh bahwa "0,075" membulatkan menjadi 0,07 daripada 0,08. Hal ini disebabkan, sebagaimana ditunjukkan oleh "Novice C", ke kombinasi aritmatika titik apung yang memiliki presisi hingga dan representasi basis-2 . Angka terdekat ke 0,075 yang sebenarnya bisa direpresentasikan sedikit lebih kecil, maka pembulatan keluar berbeda dari yang mungkin Anda harapkan secara naif.

Perhatikan juga bahwa ini berlaku untuk setiap penggunaan aritmatika titik apung non-desimal, misalnya C dan Java keduanya memiliki masalah yang sama.

Untuk menunjukkan lebih detail, kami meminta Python untuk memformat angka dalam format "hex":

0.075.hex()

yang memberi kami: 0x1.3333333333333p-4. Alasan untuk melakukan ini adalah bahwa representasi desimal normal sering melibatkan pembulatan dan karenanya bukan bagaimana komputer benar-benar "melihat" nomor tersebut. Jika Anda tidak terbiasa dengan format ini, beberapa referensi yang bermanfaat adalah dokumen Python dan standar C .

Untuk menunjukkan bagaimana angka-angka ini bekerja sedikit, kita dapat kembali ke titik awal dengan melakukan:

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

yang harus dicetak 0.075. 16**13karena ada 13 digit heksadesimal setelah titik desimal, dan2**-4 karena eksponen hex adalah basis-2.

Sekarang kami memiliki beberapa gagasan tentang bagaimana float diwakili, kami dapat menggunakan decimalmodul untuk memberi kami lebih presisi, menunjukkan kepada kami apa yang terjadi:

from decimal import Decimal

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

memberi: 0.07499999999999999722444243844dan semoga menjelaskan mengapa round(0.075, 2)dievaluasi0.07

Sam Mason
sumber
1
Ini adalah penjelasan yang bagus tentang mengapa 0,075 dibulatkan menjadi 0,07 pada level kode , tetapi kita (dalam ilmu fisika) telah diajarkan untuk selalu membulatkan ke atas, bukan ke bawah. Jadi perilaku yang diharapkan sebenarnya memiliki 0,08 sebagai hasilnya, masalah presisi floating point meskipun.
Gabriel
1
Saya tidak yakin di mana kebingungan Anda: ketika Anda memasukkan 0,075 Anda benar-benar memasukkan ~ 0,07499 (seperti di atas), yang dibulatkan sesuai dengan aturan matematika normal. jika Anda menggunakan tipe data (seperti desimal floating point ) yang bisa mewakili 0,075 maka itu memang harus bulat ke 0,08
Sam Mason
Saya tidak bingung. Ketika saya memasukkan 0,075 saya sebenarnya memasukkan 0,075. Apa pun yang terjadi dalam matematika floating point di dalam kode saya tidak peduli.
Gabriel
@Gabriel: Dan jika Anda telah sengaja masuk 0.074999999999999999, apa yang Anda harapkan untuk mendapatkan dalam kasus itu?
Mark Dickinson
@ MarkDickinson itu tergantung. Satu angka penting: 0,07, dua: 0,075.
Gabriel
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

Mudah-mudahan mengambil yang terbaik dari semua jawaban di atas (dikurangi bisa menjadikannya sebagai lambda satu baris;)). Belum dieksplorasi, silakan edit jawaban ini:

round_to_n(1e15 + 1, 11)  # 999999999999999.9
AJP
sumber
4

Saya memodifikasi solusi indgar untuk menangani angka negatif dan angka kecil (termasuk nol).

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)
ryan281
sumber
Mengapa tidak menguji saja x == 0? Jika Anda menyukai one-liner, adil return 0 if x==0 else round(...).
pjvandehaar
2
@ pjvandehaar, Anda benar untuk kasus umum dan saya harus memasukkan itu. Selain itu, untuk perhitungan numerik saya perlu melakukan kita kadang-kadang mendapatkan angka seperti 1e-15. Dalam aplikasi kami, kami ingin perbandingan dua angka kecil (satu di antaranya mungkin nol) dianggap sama. Juga beberapa orang ingin membulatkan angka kecil (bisa 1e-9, 1e-15, atau bahkan 1e-300) menjadi nol.
ryan281
1
Menarik. Terima kasih telah menjelaskannya. Dalam hal ini, saya sangat suka solusi ini.
pjvandehaar
@Morgoth Ini adalah masalah yang menarik dan sulit. Seperti yang Anda tunjukkan, nilai yang dicetak tidak menunjukkan 3 digit signifikan, tetapi nilainya benar (misalnya 0.970 == 0.97). Saya pikir Anda bisa menggunakan beberapa solusi cetak lainnya seperti f'{round_sig(0.9701, sig=3):0.3f}'jika Anda ingin nol dicetak.
ryan281
3

Jika Anda ingin membulatkan tanpa melibatkan string, tautan yang saya temukan terkubur dalam komentar di atas:

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

menurut saya yang terbaik. Kemudian ketika Anda mencetak dengan deskriptor pemformatan string apa pun, Anda mendapatkan hasil yang masuk akal, dan Anda bisa menggunakan representasi numerik untuk keperluan perhitungan lainnya.

Kode pada tautan adalah tiga baris: def, doc, dan return. Ini memiliki bug: Anda perlu memeriksa logaritma yang meledak. Itu mudah. Bandingkan input dengan sys.float_info.min. Solusi lengkapnya adalah:

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

Ini berfungsi untuk nilai numerik skalar apa pun, dan n bisa menjadi floatjika Anda perlu mengubah respons karena alasan tertentu. Anda benar-benar dapat mendorong batas ke:

sys.float_info.min*sys.float_info.epsilon

tanpa memprovokasi kesalahan, jika karena alasan tertentu Anda bekerja dengan nilai sangat kecil.

Mengantuk
sumber
2

Saya tidak bisa memikirkan apa pun yang bisa menangani ini di luar kotak. Tapi itu ditangani dengan cukup baik untuk angka floating point.

>>> round(1.2322, 2)
1.23

Bilangan bulat lebih rumit. Mereka tidak disimpan sebagai basis 10 dalam memori, jadi tempat yang signifikan bukanlah hal yang wajar untuk dilakukan. Ini cukup sepele untuk diterapkan begitu mereka adalah string.

Atau untuk bilangan bulat:

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

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

Jika Anda ingin membuat fungsi yang menangani angka apa pun, preferensi saya adalah mengonversikan keduanya menjadi string dan mencari tempat desimal untuk memutuskan apa yang harus dilakukan:

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

Pilihan lain adalah memeriksa jenisnya. Ini akan jauh kurang fleksibel, dan mungkin tidak akan bermain bagus dengan nomor lain seperti Decimalobjek:

>>> def roundall2(n, sigfigs):
...   if type(n) is int: return intround(n, sigfigs)
...   else: return round(n, sigfigs)
Tim McNamara
sumber
Hanya mengacaukan string tidak akan membulatkan angka. 1999 dibulatkan menjadi 1 angka penting adalah 2000, bukan 1000.
Peter Graham
Ada diskusi yang bagus tentang masalah ini yang diarsipkan di ActiveState code.activestate.com/lists/python-tutor/70739
Tim McNamara
2

Jawaban yang diposting adalah yang terbaik yang tersedia ketika diberikan, tetapi memiliki sejumlah keterbatasan dan tidak menghasilkan angka signifikan yang benar secara teknis.

numpy.format_float_positional mendukung perilaku yang diinginkan secara langsung. Fragmen berikut mengembalikan float yang xdiformat menjadi 4 angka penting, dengan notasi ilmiah ditekan.

import numpy as np
x=12345.6
np.format_float_positional(x, precision=4, unique=False, fractional=False, trim='k')
> 12340.
Musim gugur
sumber
Dokumentasi (pindah ke numpy.org/doc/stable/reference/generated/… ) menyatakan bahwa fungsi ini mengimplementasikan algoritma Dragon4 (dari Steele & White 1990, dl.acm.org/doi/pdf/10.1145/93542.93559 ). Ini menghasilkan hasil yang mengganggu, misalnya 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'). Saya tidak memeriksa Dragon4 sendiri.
Rainald62
0

Saya juga mengalami hal ini tetapi saya membutuhkan kontrol atas jenis pembulatan. Jadi, saya menulis fungsi cepat (lihat kode di bawah) yang dapat mengambil nilai, jenis pembulatan, dan angka-angka penting yang diinginkan.

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))
drew.ray
sumber
0

Menggunakan format python 2.6+ gaya baru (karena%-style sudah usang):

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

Dalam python 2.7+ Anda dapat menghilangkan 0s terkemuka .

eddygeek
sumber
Dengan versi python apa? Python 3.6.3 | Anaconda, Inc. | (default, 13 Okt 2017, 12:02:49) memiliki masalah pembulatan lama yang sama. "{0}". Format (float ("{0: .1g}". Format (0,075))) menghasilkan '0,07', bukan '0,08'
Don Mclachlan
@DonMclachlan Saya telah menambahkan penjelasan mengapa ini diharapkan di stackoverflow.com/a/56974893/1358308
Sam Mason
0

Fungsi ini melakukan putaran normal jika jumlahnya lebih besar dari 10 ** (- decimal_positions), jika tidak menambahkan lebih banyak desimal hingga jumlah posisi desimal yang berarti tercapai:

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)

Semoga ini bisa membantu.

Ettore Galli
sumber
0

https://stackoverflow.com/users/1391441/gabriel , apakah yang berikut ini menanggapi kekhawatiran Anda tentang rnd (.075, 1)? Peringatan: mengembalikan nilai sebagai pelampung

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
Don Mclachlan
sumber
0

Ini mengembalikan string, sehingga hasil tanpa bagian fraksional, dan nilai-nilai kecil yang akan muncul dalam notasi E ditampilkan dengan benar:

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))
Gnubie
sumber
0

Diberikan pertanyaan sehingga dijawab dengan seksama mengapa tidak menambahkan yang lain

Ini cocok dengan estetika saya sedikit lebih baik, meskipun banyak di atas sebanding

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)

Ini berfungsi untuk bilangan individual dan array numpy, dan harus berfungsi baik untuk bilangan negatif.

Ada satu langkah tambahan yang mungkin kita tambahkan - np.round () mengembalikan angka desimal bahkan jika bulat adalah bilangan bulat (yaitu untuk significantFigures = 2 kita mungkin berharap untuk mendapatkan kembali -460 tetapi sebaliknya kita mendapatkan -460.0). Kami dapat menambahkan langkah ini untuk memperbaiki itu:

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

Sayangnya, langkah terakhir ini tidak akan berhasil untuk array angka - Saya akan menyerahkan kepada Anda pembaca yang budiman untuk mencari tahu jika Anda perlu.

angin barat
sumber
0

The sigfig paket / selimut perpustakaan ini. Setelah menginstal Anda dapat melakukan hal berikut:

>>> 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
Hiperaktif
sumber
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
LetzerWille
sumber