浮動小数点演算に於ける誤差

JavaScriptのfloatで正確な比較を行う – Qiita

(可愛いイラストだなあ……)
(JSにもdecimal系のライブラリがあった様な気がするけど)

2進法の浮動小数点数に対する算術演算に於ける丸め誤差の影響は
そもそも不必要な(無意味な)桁に着目する事に起因するので,
有効数字を考慮すれば問題にはならないけども,
愚直な解法としては十進浮動小数点算術を用いる事が考えられる.

 
In [1]: a = 0.3 – 0.2
In [2]: b = 0.2 – 0.1
In [3]: a == b
Out[3]: False
In [4]: a, b
Out[4]: (0.09999999999999998, 0.1)
In [5]: from decimal import *
In [6]: ad = Decimal(0.3) – Decimal(0.2)
In [7]: bd = Decimal(0.2) – Decimal(0.1)
In [8]: ad == bd
Out[8]: False
In [9]: ad
Out[9]: Decimal(‘0.09999999999999997779553950750’)
In [10]: bd
Out[10]:Decimal(‘0.1000000000000000055511151231’)
In [11]: ad = Decimal(‘0.3’) – Decimal(‘0.2’)
In [12]: bd = Decimal(‘0.2’) – Decimal(‘0.1’)
In [13]: ad
Out[13]: Decimal(‘0.1’)
In [14]: bd
Out[14]: Decimal(‘0.1’)
In [15]: ad == bd
Out[15]: True
In [16]: ad, bd
Out[16]: (Decimal(‘0.1’), Decimal(‘0.1’))

 

ただ,僕はこちらの方がリーズナブルだと思う.

In [17]: import math
In [18]: math.isclose(a, b)
Out[18]: True

或いは,きちんと有効数字を考える.

def sigfigr(x, n=None, e_print=True):
    from math import log10, floor

    dp = -floor(log10(abs(x)))
    temp = x * 10**dp

    if n is None:
        n = 8
        sigfig = round(temp, n)
    else:
        sigfig = round(round(temp, n) + 10**(-n), n-1) if n < len(str(temp))-1 and int(str(round(temp, n))[n+1]) > 4 else round(temp, n-1)

    if e_print:
        return f'{sigfig}' + f'{10**(-dp):.1e}'[3:]
    else:
        return float(f'{sigfig}' + f'{10**(-dp):.1e}'[3:])
sigfigr(0.3-0.2, 1, False), sigfigr(0.2-0.1, 1, False)

(0.1, 0.1)

 
 
 

def sigfigr(x, n=None, e_print=True):
    from math import log10, floor

    dp = -floor(log10(abs(x)))
    temp = x * 10**dp

    if n is None:
        n = 8
        sigfig = round(temp, n)
    else:
        sigfig = round(round(temp, n) + 10**(-n), n-1) if n < len(str(temp))-1 and int(str(round(temp, n))[n+1]) > 4 else round(temp, n-1)

    if e_print:
        return f'{sigfig}' + f'{10**(-dp):.1e}'[3:]
    else:
        return float(f'{sigfig}' + f'{10**(-dp):.1e}'[3:])


sigfigr(1234243, 3), sigfigr(13, 1), sigfigr(0.0232, 3), sigfigr(5.015, 3), sigfigr(0.333, 2), sigfigr(0.2145, 3), sigfigr(1.5235, 4), sigfigr(0.1+0.1+0.1, 1), sigfigr(1 / 3 * 3, 1), sigfigr(1 / 3, 1)

(‘1.23e+06’,
‘1.0e+01’,
‘2.32e-02’,
‘5.02e+00’,
‘3.3e-01’,
‘2.15e-01’,
‘1.524e+00’,
‘3.0e-01’,
‘1.0e+00’,
‘3.0e-01’)

sigfigr(1234243, 3, False), sigfigr(13, 1, False), sigfigr(0.0232, 3, False), sigfigr(5.015, 3, False), sigfigr(0.333, 2, False), sigfigr(0.2145, 3, False), sigfigr(1.5235, 4, False), sigfigr(0.1+0.1+0.1, 1, False), sigfigr(1 / 3 * 3, 1, False), sigfigr(1 / 3, 1, False)

(1230000.0, 10.0, 0.0232, 5.02, 0.33, 0.215, 1.524, 0.3, 1.0, 0.3)

 
 

関連:
float?Decimal?Sympy?浮動小数点演算

Pythonで有効数字

最も近い10の倍数を求める

カテゴリー: 未分類 パーマリンク