Щоб безпосередньо відповісти на питання, ось моя версія з використанням імен з функції 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)
Моя основна причина розміщення цієї відповіді - це коментарі, в яких скаржиться, що "0,075" кругляє до 0,07, а не 0,08. Це пов'язано, як вказувало "Новачок С", комбінацією арифметики з плаваючою комою, що має як кінцеву точність, так і представлення бази-2 . Найближче число до 0,075, яке насправді може бути представлене, трохи менше, отже, округлення виходить інакше, ніж можна наївно очікувати.
Також зауважте, що це стосується будь-якого використання арифметики з плаваючою комою без десяткових знаків, наприклад, C і Java мають однакові проблеми.
Щоб показати більш докладно, ми просимо Python відформатувати число у форматі "hex":
0.075.hex()
який дає нам: 0x1.3333333333333p-4
. Причиною цього є те, що звичайне десяткове представлення часто включає округлення, а значить, не те, як комп'ютер насправді "бачить" число. Якщо ви не звикли до цього формату, кілька корисних посилань є документи Python і стандартний C .
Щоб показати, як ці номери трохи працюють, ми можемо повернутися до початкової точки, зробивши:
0x13333333333333 / 16**13 * 2**-4
який повинен роздрукуватись 0.075
. 16**13
це тому, що після десяткової коми є 13 шістнадцяткових цифр, і 2**-4
це тому, що шістнадцяткові показники є базовою-2.
Тепер ми маємо деяке уявлення про те, як представлені поплавці, ми можемо використовувати decimal
модуль, щоб дати нам ще точність, показуючи нам, що відбувається:
from decimal import Decimal
Decimal(0x13333333333333) / 16**13 / 2**4
даючи: 0.07499999999999999722444243844
і сподіваємось пояснити, чому round(0.075, 2)
оцінює0.07