HOWTO · Python
Python で数値を有効数字に丸める方法
round()、math、書式設定、Decimal、sigfig、NumPy を使って Python の数値を有効数字に丸める方法を学びます。
このページの内容
数値を選択した有効数字の桁数に丸めるには、その 10 進数の大きさを求め、対応する小数位の数を round() に渡します。たとえば、1,342 を有効数字 1 桁に丸めると 1,000 になります。単一の値であれば組み込み関数で十分です。繰り返し計算にはヘルパーを、結果をテキストのままにしたい場合は書式設定を、10 進数の丸め規則が重要な場合は Decimal を、配列には NumPy を使用してください。
Python’s round() で有効数字に丸める
round(number, ndigits) は小数位の数まで丸めます。有効数字については、ndigits を digits - 1 - floor(log10(abs(number))) として計算します。1,342 と有効数字 1 桁の場合、これは 1 - 1 - 3、つまり -3 になるため、Python は最も近い千の位に丸めます。
この例を実行してください。
print(round(1342, -3))
1000
Python は中間の場合に偶数への丸め(ties-to-even)を使用するため、値が 2 つの丸められた値のちょうど中間にある場合、最後に残る桁は偶数になります。これは、中間の場合に常にゼロから離れる方向に丸めるのとは異なります。負の ndigits は、十、百、またはそれより大きな 10 の冪に丸めます。round() は数値を返します。末尾のゼロを表示上の慣例として保持しません。浮動小数点入力の場合、格納された二進近似も見かけ上の 10 進数の中間ケースに影響することがあります。
math ヘルパーで有効数字に丸める
ヘルパーは、10 を底とする大きさから小数位の数を計算できます。次のバージョンは、正の整数の桁数と有限の数値を受け入れ、ゼロはそのまま返します。サポートされていない桁数や有限でない入力に対しては ValueError を発生させます。これは、log10() がそれらの値に対して有限の 10 進数の大きさを決定できないためです。
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 の場合、10 進指数が -4 未満、または p 以上の場合は科学的記数法を使用し、それ以外の場合は通常の記数法を使用します。精度 3 の場合、0.0001 と 999 は通常の記数法を使用し、0.00001 と 1000 は科学的記数法を使用します。書式設定は文字列を返すため、目的が表示である場合に便利です。選択した表現を保持するにはその文字列を保持し、後続の数値演算が必要な場合にのみ float() で変換してください。数値に変換すると、末尾のゼロなどの表示の詳細は失われます。
たとえば、"%.3g" % 1324 は値を有効数字 3 桁で書式設定します。結果はテキストであり、通常の記数法と科学的記数法の正確な選択はフォーマッタが行います。
sigfig で有効数字に丸める
サードパーティ製パッケージ sigfig は、sigfigs 引数を通じて有効数字の数を受け入れます。使用する前に、ご使用の環境にパッケージをインストールしてください。たとえば、パッケージの呼び出しは sigfig.round(1324, sigfigs=2) です。これは、パッケージの動作と書式設定がアプリケーションに適している場合に便利です。上記の組み込みまたはヘルパーのアプローチには必要ありません。
decimal.Decimal で有効数字に丸める
Decimal は 10 進演算と明示的な丸めモードをサポートします。入力の 10 進数字が重要な場合は、文字列から構築してください。既存の浮動小数点数を変換しても、その浮動小数点数が格納していなかった情報を回復することはできません。この例では、有限でゼロでない 10 進数を要求された精度にスケーリングし、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 は 1 つの方針にすぎません。アプリケーションの規則に一致する場合は、ROUND_HALF_EVEN のようなモードを選択してください。10 進演算は依然としてアクティブなコンテキスト精度によって制限されることがあるため、無制限の精度を約束するものではありません。
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]