数値解析日記

数値解析関係のネタ帳。C++,pythonなど

メモ:as_interger_ratio()では正確に元の分数には戻せない

as_interger_ratio()では正確に元の分数には戻せない

a = 0.1 を区間型に代入する際にうまく包含できないので、色々実験してみた。

何が問題なのか?

import pint as pn
x=pn.interval(0.1)

と、2進数小数で表現不可能な数字なので下限と上限は

format(x.inf,'.17g')
'0.10000000000000001'
format(x.sup,'.17g')
'0.10000000000000001'

となり、0.1はうまく包含できない

解決策になりそうだったもの

pythonのfloat型にはas_integer_ratio()という関数があり、

a = 0.1
x,y = a.as_integer_ratio()
print(x)
3602879701896397
print(y)
36028797018963968
x/y
0.1

となり、0.1の分母と分数を取得できる
これを用いれば、さきほどのinterval型への代入問題を解決できそうだが

sup = pn.roundfloat.rddiv(x, y, pn.roundmode.up)
inf = pn.roundfloat.rddiv(x, y, pn.roundmode.down)
format(sup,'.17g')
'0.10000000000000001'
format(inf,'.17g')
'0.10000000000000001'

となり、0.1を包含するように計算できない。
なぜならば a=0.1 とした時点で 0.1 から、0.1よりずれた小数に近似されるため、as_interger_ratio で取得できる分母と分子は 0.1よりずれた小数に合うように取得されるためである。

誤解回避

0.1...となる分数を取得することは可能だが
厳密に0.1になるような分数はas_integer_ratioでは取得できない
(このように厳密に計算するとき以外は大した問題にならないと思われる)