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**13
karena 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 decimal
modul untuk memberi kami lebih presisi, menunjukkan kepada kami apa yang terjadi:
from decimal import Decimal
Decimal(0x13333333333333) / 16**13 / 2**4
memberi: 0.07499999999999999722444243844
dan semoga menjelaskan mengapa round(0.075, 2)
dievaluasi0.07