HOWTO · Python
如何在 Python 中將數字四捨五入到有效數字
了解如何使用 round()、math、格式化、Decimal、sigfig 和 NumPy 將 Python 數字四捨五入到有效數字。
本頁內容
若要將數字四捨五入到所選的有效數字位數,請找出它的十進位數量級,並將相應的小數位數傳遞給 round()。例如,1,342 四捨五入到一位有效數字會變成 1,000。對於單一值,內建函式就足夠了;重複計算時使用輔助函式,結果應保持為文字時使用格式化,十進位四捨五入規則重要時使用 Decimal,陣列則使用 NumPy。
使用 Python’s round() 四捨五入到有效數字
round(number, ndigits) 會四捨五入到若干小數位。對於有效數字,將 ndigits 計算為 digits - 1 - floor(log10(abs(number)))。對於 1,342 和一位有效數字,這是 1 - 1 - 3,即 -3,因此 Python 會四捨五入到最接近的千位。
執行此範例:
print(round(1342, -3))
1000
Python 對於正好位於中間的情況使用四捨五入到偶數(ties-to-even),因此當值正好位於兩個四捨五入值的中間時,最後保留的數字是偶數。這與總是將中間情況遠離零四捨五入不同。負的 ndigits 會四捨五入到十位、百位或更大的 10 的冪。round() 傳回一個數字;它不會將尾隨零保留為顯示慣例。對於浮點輸入,儲存的二進位近似值也可能影響表面上的十進位中間情況。
使用 math 輔助函式四捨五入到有效數字
輔助函式可以從以 10 為底的數量級計算小數位數。以下版本接受正整數位數和有限的數值,並將零原樣傳回。對於不受支援的位數或非有限輸入,它會引發 ValueError,因為 log10() 無法為這些值確定有限的十進位數量級。
from math import floor, isfinite, log10
def round_significant(value, digits):
if not isinstance(digits, int) or digits < 1:
raise ValueError("digits must be a positive integer")
if not isfinite(value):
raise ValueError("value must be finite")
if value == 0:
return value
places = digits - 1 - floor(log10(abs(value)))
return round(value, places)
print(round_significant(1324, 2))
該公式適用於正和負的有限值,因為它使用 abs(value) 來找出數量級,而 round() 會保留正負號。它遵循 Python 的四捨五入到偶數規則。在計算對數之前,使用 math.isfinite() 來決定輸入是否受支援;如果您的應用程式需要,請單獨處理 NaN 和無限大。
使用字串格式化四捨五入到有效數字
%g 格式將其精度用作有效數字位數。當精度為 p 時,如果十進位指數小於 -4 或大於或等於 p,它使用科學記號;否則,它使用普通記號。對於精度 3,0.0001 和 999 使用普通記號,而 0.00001 和 1000 使用科學記號。格式化傳回一個字串,當目標是呈現時這很有用。保留該字串以保留其所選的表示方式;僅在需要後續數值運算時才使用 float() 轉換它。轉換為數字會捨棄尾隨零等顯示細節。
例如,"%.3g" % 1324 會以三位有效數字格式化該值。結果是文字,普通記號和科學記號之間的確切選擇由格式化程式做出。
使用 sigfig 四捨五入到有效數字
第三方套件 sigfig 透過其 sigfigs 引數接受有效數字的位數。在使用之前,請在您的環境中安裝該套件。例如,套件呼叫是 sigfig.round(1324, sigfigs=2)。當套件的行為和格式化適合您的應用程式時,這很方便;對於上述內建或輔助方法,它不是必需的。
使用 decimal.Decimal 四捨五入到有效數字
Decimal 支援十進位算術和明確的四捨五入模式。當輸入中的十進位數字重要時,請從字串建構它;轉換現有的浮點數無法恢復該浮點數未儲存的資訊。此範例將有限的非零十進位數縮放到所要求的精度,並使用 ROUND_HALF_UP 將中間情況遠離零四捨五入。
from decimal import Decimal, ROUND_HALF_UP
def round_decimal_significant(value, digits):
if not isinstance(digits, int) or digits < 1:
raise ValueError("digits must be a positive integer")
number = Decimal(str(value))
if not number.is_finite():
raise ValueError("value must be finite")
if number.is_zero():
return number
quantum = Decimal(1).scaleb(number.adjusted() - digits + 1)
return number.quantize(quantum, rounding=ROUND_HALF_UP)
print(round_decimal_significant("1324", 2))
結果仍保持為 Decimal。ROUND_HALF_UP 只是一種策略;當它符合您的應用程式規則時,請選擇如 ROUND_HALF_EVEN 的模式。十進位算術仍可能受到作用中內容精度的限制,因此它不保證無限的精度。
使用 NumPy 將陣列四捨五入到有效數字
當輸入是陣列時,NumPy 很有用,但 numpy.around() 接受的是小數位而不是有效數字。對於有限的非零值,使用 digits - 1 - floor(log10(abs(value))) 計算小數位數,並將其傳遞給 numpy.around()。對於陣列,逐元素計算數量級,並在取對數之前處理零和非有限值。NumPy 是一個額外的相依性;此方法遵循浮點四捨五入行為,並且不保留顯示零。
以下範例僅四捨五入有限的非零元素。它將零、NaN 以及正或負無限大保持不變。傳回的值是具有浮點元素的 NumPy ndarray。NumPy 是一個額外的相依性,因此請在執行此範例之前安裝它。
import numpy as np
values = np.array([1234.5, -1234.5, 0.0, np.nan, np.inf, -np.inf])
digits = 3
rounded = values.copy()
finite_nonzero = np.isfinite(values) & (values != 0)
for index in np.flatnonzero(finite_nonzero):
places = digits - 1 - int(np.floor(np.log10(abs(values[index]))))
rounded[index] = np.around(values[index], decimals=places)
print(rounded.tolist())
[1230.0, -1230.0, 0.0, nan, inf, -inf]