【Python学習帳】028_Mathモジュールと精度
初学者を対象と初学者を対象としている京都大学の無料Python教材の学習中です。
「プログラミング演習 Python 2021」
Version2021_10_08_01.pdf
をCC-BY-NC-NDライセンスに従って引用します。
第5章の制御構造の勉強をしてきました。
前回から
5.7 Python での数学関数
を学んでいます。
3.7系の日本語ドキュメントも読んでみました。
math.pi
利用可能なだけの精度の数学定数 π = 3.141592... (円周率)。
と精度についての注釈が付いています。精度に関しては教材でも何度か話題に取り上げています。
精度はプログラミングで数値データを扱う処理で本来は念頭に置いておかないといけない注意点だと思います。
今回はMathモジュールなど関数利用に関してBingChatと質疑をいくつかしましたので紹介しておきます。
Q1.
math.fsum(iterable): iterable 中の値の浮動小数点数の正確な和を返します。
とありますが、
sum(iterable)
と異なるということでしょうか?
A1. はい、math.fsum(iterable) と sum(iterable) は異なります。sum(iterable) は組み込み関数で、イテラブルオブジェクトの要素を左から右へ足し合わせて総和を返します。しかし、浮動小数点数の計算には誤差が生じることがあります。例えば、10個の浮動小数点数0.1をリストにして、すべての要素を足すと、0.9999999999999999となり、1.0に届きません1。
math.fsum(iterable) はMathモジュールの関数で、イテラブルオブジェクト中の値の浮動小数点数の正確な和を返します。複数の部分和を追跡することで精度のロスを防ぎます。上と同じ計算を math.fsum(iterable) を使って実行すると、1.0となります。
このように、高い精度を求める場合は、math.fsum(iterable) 関数を使う方がよいでしょう。
この件は京都大学の無料Python教材「プログラミング演習 Python 2021」では
http://hdl.handle.net/2433/265459
Version2021_10_08_02.pdf
のコラム編で詳しく説明してくれています。
1.2 2進数で浮動小数点数を扱うことの嫌な点
高速な計算を実現するために,コンピュータ内部では基数を 10 とする 10 進数で
はなく,2 とする 2 進数が広く用いられています.整数を扱う際には 10 進数も 2 進数も本質的な違いはありませんが,小数では差異が出てしまいます.
10 進数の小数では 1/3 は 0.33333… となり有限の桁数では表せません,これは
十進数の小数が各桁の大きさ 1/10, 1/100, 1/1000 … のそれぞれ 0 ~9 倍の和として表そうとするためです.小学校で習ったときには違和感を持たれた方も少なくな
いと思いますが,もう慣れましたよね.
2 進数の小数では 1/2, 1/4, 1/8, 1/16 …が各桁の大きさとなり,その 0 倍か 1 倍の和で数値を表します.このため,10 進数を使う我々がしばしば用いる 0.1 が2
進数では正確に表せません.小学校の時の違和感がコンピュータのおかげで私たち
が日常的に用いる 10 進数の扱いで生じるのです.
実際,Python で 0.1 を 3 回加えたものが 0.3 と等しいかどうかを評価する以下
の式について試してみると
0.1 + 0.1 + 0.1 == 0.3
その値は False となってしまいます.
科学や技術の計算では,十分な精度さえあればよい場合がほとんどで 0.1 が厳密
な値をとっていることはあまり問題になりません 1.しかしながら,お金を扱う会計
計算では,金額としてかなりの桁数を扱う一方で,金利が 0.01 (1%) など,10 進
数の小数で扱われることが多いです.このため,十進数の小数が正確に表せないこ
とは避ける必要がでてきます.会計にコンピュータを用いるためには,コンピュー
タ内部でも 10 進数の計算をすることが求められます.Python では正確な 10 進数
で演算する decimal というモジュールが用意されています.
参考文献として紹介されている
に、冒頭紹介した「利用可能なだけの精度」の具体的な例も示されていますのでご興味あれば。
以下は余談ですが、私が下記のようなアホな質問をしても、Chatはきちんと教えてくれます。
Q2. math.fabs(x): x の絶対値を返します。
との回答ですが、
math.abs(x)
では動作しないのですか?
A2. math.abs(x) ではなく、abs(x) と書くと動作します。
abs(x) は組み込み関数で、Mathモジュールには含まれていません。
abs(x) は引数の型に応じて整数や浮動小数点数や複素数の絶対値を返します。math.fabs(x) はMathモジュールの関数で、引数が整数や浮動小数点数でなく複素数だとTypeErrorを送出します。math.fabs(x) は常に浮動小数点数の絶対値を返します。
ちなみに絶対値の算出方法も各種ありなかなかに奥が深いようでして、下記の記事のように掘り下げて解説して下さっている方もいました。
今回もひとさまの知恵に頼りっきりの学習となりました。
次回は関数でのデータ変換に進みます。