浮動小数点かround()の深みを覗いてしまった【Python勉強ちう】


このエントリーをはてなブックマークに追加

ここからちょっと広告です。

広告は以上です。

round()という、四捨五入っぽいことをする関数をいじっていて、不思議な結果に気付きました。
具体的にいうと、

round(10.50001)
11

なのに、

round(10.50000000000000000000000000001)
10

なのです。

どうやら、何桁目くらいからか、結果が変わる様子。
同じ計算をしているのに。

そこで、こんなコードを書いて、何桁目から11が10になるのか、調べようとしました。

【コード】 https://gist.github.com/kotoripiyopiyo/64598757885cae50537d870d424198d1#file-gistfile1-txt

しかし……
結果は想像の斜め上をいくものでした。こんな感じ。

Roundfloat2020080301

下から3行目、最後が「1」じゃなくて「2」になってるのは何故!?
そして次の行で、いきなり0が全部なくなるのは何故!?

自分で調べてもよくわからなかったので、聞いて回ったところ、どうも以下のことが原因でこうなっている様子(教えてくれた友だちたち、ありがとうございます!)。

● そもそもプログラムで使う小数は小数じゃなくて「浮動小数点」ってやつで、誤差が出る小数っぽい何からしい(参考:Pythonのドキュメント浮動小数点演算、その問題と制限浮動小数点って何?

● round()は四捨五入じゃなくてbankers rounding(銀行家の丸め)っていうのらしい(参考:Pythonで小数・整数を四捨五入するroundとDecimal.quantize

これらがどう絡みあって上記のような結果になるのか、そのカラクリまでは、非常に難しく、理解に時間がかかりそうです。

ただ、問題の箇所と理由は発見できました。
僕のプログラムの場合の問題は、たとえば「10.50000001 is 11」と表示するとき、「10.50000001」の部分は、数字ではなく、こういう文字列として扱えばイケるはずです。

だから、まず10.50000001という数字の羅列を文字列として作って、そのあとで、これを数字にしてround()関数に放り込むことにしました。

【コード】
https://gist.github.com/kotoripiyopiyo/64598757885cae50537d870d424198d1#file-gistfile1-txt

すると……

Roundfloat2020080302

はい! 望み通りの結果が出ました!
どうやらPythonのround()関数は、10.5000000000000001辺りから、答えが11→10に変わるようです。

いつもの通り全く役に立たないプログラムですが、僕がスッキリしたので、記念として取っておこうと思います。

それにしてもこの問題、根が深いのに、完全に理解しておかないと、あちこちで想定外の動きを起こしそう……

なので、とりあえず教科書はこなしながら(今は機械学習を少し離れて、『退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミング』で基礎を学んでます)、パラでこの件については勉強を深めていきたいと存じます。

Ads by Google

コメント

コメントは、Twitterやはてブに、以下のボタンから本記事のアドレスつきでツイート/ブクマしていただくと、上にあるzenbackのウィジェットに反映されます。
  このエントリーをはてなブックマークに追加
または同ウィジェット内のFacebookコメントでお願いしますー。

Facebookのシェアは……されても誰だかわからないのですが、シェア自体は嬉しいので、下にボタンを置かせていただきます。よろしくお願いします。