浮動小数点数の改善点
却下されたPEP-754では、PythonのIEEE 754完全準拠が提案されていました。これが却下されたのは、NaN
(非数)や正負の無限大など、IEEE 754特殊値を処理するのに、Python(CPython実装)がCライブラリに依存しているためです。異なるプラットフォーム間に多くの不整合があります。それでも、Python 3.0では(2.6でも)浮動小数点数に多くの改良が加えられ、IEEE 754標準の実装も大幅に進みました。
文字列を浮動小数点数に変換するfloat()
関数は、nan
、+inf
(またはinf
)、および-inf
を認識し、IEEE 754の非数、正の無限大、負の無限大に変換するようになりました(大文字小文字は区別されず、NaN
、INF
なども有効です)。
math
モジュールに、isnan()
関数とisinf()
関数が追加されました。isinf()
関数では、inf
、+inf
、-inf
は区別されません。以下に使用例を示します。
>>> float('nan') nan >>> float('NaN') # Any case works nan >>> float('+inf') inf >>> float('-inf') -inf >>> float('INF') inf >>> float('nan') + float('inf') nan >>> float('inf') + float('-inf') nan >>> float('inf') - float('-inf') inf >>> import math >>> math.isnan(float('nan')) True >>> math.isinf(float('inf')) True >>> math.isinf(float('-inf')) True >>> math.isinf(float('nan')) False >>> math.isnan(float('-inf')) False
math
モジュールには、copysign(x, y)
関数も追加されました。この関数は、x
の絶対値に符号y
を付けて返します。-1と1を返す単純なsign()
や、ispositive()
、isnegative()
といった関数ではなく、どうしてこの関数なのか、よく分かりません。ドキュメントにもごく簡潔な記述しかありません。
>>> help(math.copysign) Help on built-in function copysign in module math: copysign(...) copysign(x,y) Return x with the sign of y.
とはいえ、copysign()
関数はこの説明のとおりに動作します。ただし、NaN
の場合は別です。NaN
の符号をコピーしようとした場合の結果は一貫せず、Mac OS Xでは負の符号、Windowsでは正の符号になります。クローズ済みのバグによると、この動作で問題なし、とされていますが、同意できません。NaN
は非数なので、符号はありません。NaN
から符号をコピーしようとすることは、数値ではないそれ以外の値(文字列、リスト、オブジェクト)から符号をコピーしようとするのと同じであり、例外を発生させるべきです。
math
モジュールには、浮動小数点数関連の関数がこれ以外にも追加されています。math.fsum()
は、繰り返し可能オブジェクト(iterable)から数値のストリームの合計を出す関数で、sum()
組み込み関数とは異なり、部分合計による精度ロスを入念に回避しています。いずれかの数値がNaN
の場合、結果はNaN
になります。部分合計が+inf
または-inf
に達すると、sum()
関数はそれを結果として返しますが、math.fsum()
関数はOverflowError例外を発生させます。これは、よりIEEE 754に沿った動作です。
>>> sum([1e308, 1, -1e308]) 0.0 >>> math.fsum([1e308, 1, -1e308]) 1.0 >>> sum([1e100, 1, -1e100, -1]) -1.0 >>> math.fsum([1e100, 1, -1e100, -1]) 0.0 >>> x = [1e308, 1e308, -1e308] >>> sum(x) inf >>> math.fsum(x) Traceback (most recent call last): File "<stdin>", line 1, in <module> OverflowError: intermediate overflow in fsum >>> sum([float('nan'), 3.3]) nan >>> math.fsum([float('nan'), -float('nan')]) nan
acosh()
関数、asinh()
関数、atanh()
関数は、逆双曲線関数を計算します。log1p()
関数は1+x (base e)
の自然対数を返します。trunc()
関数は、数値の小数点以下を切り捨てて近似値の整数値を返します。
>>> math.acosh(30) 4.0940666686320855 >>> math.acosh(1) 0.0 >>> math.asinh(1) 0.88137358701954305 >>> math.asinh(0) 0.0 >>> math.atanh(0.5) 0.54930614433405489 >>> math.log1p(2) 1.0986122886681098 >>> math.trunc(-1.1) -1 >>> math.trunc(-1.9) -1 >>> math.trunc(1.1) 1 >>> math.trunc(1.9) 1 >>> math.trunc(3.0) 3
浮動小数点数と16進文字列の間の変換を行うことができます。変換関数は、浮動小数点数を文字列表現へ、文字列表現を浮動小数点数へ変換し、10進と2進の変換の丸め誤差を発生させません(その数値を完全に表現する桁数がある場合)。float
のhex()
メソッドは文字列を返し、float.fromhex()
メソッドは文字列を(可能な限り正確に)数値に変換します。
>>> x = 4.2 >>> a.hex() '0x1.0cccccccccccdp+2' >>> float.fromhex('0x1.0cccccccccccdp+2') 4.2000000000000002
decimal
モジュールは汎用10進演算仕様バージョン1.66に更新されました。新しい機能として、exp()
やlog10()
などの基本的な算術関数のメソッドが追加されました。
>>> Decimal(1).exp() Decimal("2.718281828459045235360287471") >>> Decimal("2.7182818").ln() Decimal("0.9999999895305022877376682436") >>> Decimal(1000).log10() Decimal("3")
Decimal
オブジェクトのas_tuple()
メソッドは、符号、仮数、指数のフィールドを持つ名前付きタプルを返すようになりました(名前付きタプルについては今後の記事で説明します)。
>>> Decimal('-3.3').as_tuple() DecimalTuple(sign=1, digits=(3, 3), exponent=-1)
sys
モジュールの新しい変数float_info
は、float.hファイルから得たプラットフォームの浮動小数点数サポート情報が含まれるオブジェクトです。
>>> sys.float_info sys.floatinfo(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.2204460492503131e-16, radix=2, rounds=1)
このように、Pythonの浮動小数点数サポートは確かに向上しましたが、まだ完璧ではありません。Pythonで重要な数値演算を行うには、Numpy外部パッケージが依然として最善の策と言えます。