Python(だけでなく多くのプログラミング言語)では実数を浮動小数点 (float) の形式で取り扱います.例えば 0.5
という実数を格納した変数 a
は float
型になっています(typeの説明はここを,?
の説明はここを参照してください.).
a = 0.5
type(a)
float
?a
Type: float String form: 0.5 Docstring: Convert a string or number to a floating point number, if possible.
10進数の 0.5 という値は \( 0.5 = 1 \times 2^{-1} = \frac{1}{2}\) と表すことができることから,2進数の浮動小数点で誤差なく表現することができます.なお,f文字列の説明はここを参照してください.
a = 0.5
print(f"{a:.40f}")
0.5000000000000000000000000000000000000000
\( 0.25 = 0 \times 2^{-1} + 1 \times 2^{-2} = \frac{1}{4}\) や \( 0.125 = 0 \times 2^{-1} + 0 \times 2^{-2} + 1 \times 2^{-3} = \frac{1}{8}\) も同様に2進数の浮動小数点で誤差なく表現することができます.
a = 0.25
print(f"{a:.40f}")
a = 0.125
print(f"{a:.40f}")
0.2500000000000000000000000000000000000000 0.1250000000000000000000000000000000000000
さらに,\( 0.75 = 1 \times 2^{-1} + 1 \times 2^{-2} = \frac{1}{2} + \frac{1}{4}\) や \( 0.625 = 1 \times 2^{-1} + 0 \times 2^{-2} + 1 \times 2^{-3} = \frac{1}{2} + \frac{1}{8}\) も同様です.
a = 0.75
print(f"{a:.40f}")
a = 0.625
print(f"{a:.40f}")
0.7500000000000000000000000000000000000000 0.6250000000000000000000000000000000000000
一方で,\( \frac{1}{3}\) が 0.333...
という無限小数となって厳密に表現できないことと同様に,10進数の 0.1
は2進数の浮動小数点で無限小数となってしまいます.a = 0.1
を print
で表示すると正確に表示されているように感じられます.
a = 0.1
print(f"{a}")
0.1
しかし,正確なのは先頭から16桁程度でそれ以降の桁は正しくありません.
a = 0.1
print(f"{a:.40f}")
0.1000000000000000055511151231257827021182
上の例や次の例のように,浮動小数点形式のデータを取り扱うときには,非常に小さな誤差が含まれるということに注意してください.
a = 0.2
print(f"{a:.40f}")
a = 0.3
print(f"{a:.40f}")
a = 0.33
print(f"{a:.40f}")
a = 0.01
print(f"{a:.40f}")
a = 0.001
print(f"{a:.40f}")
0.2000000000000000111022302462515654042363 0.2999999999999999888977697537484345957637 0.3300000000000000155431223447521915659308 0.0100000000000000002081668171172168513294 0.0010000000000000000208166817117216851329
なお,Pythonではメモリが許す限り大きな桁の整数を(誤差なく)扱うことができます.
b = 123456789012345678901234567890
print(b)
123456789012345678901234567890
しかしながら,整数に 1.0
を掛けるという演算を行ったことで結果は浮動小数点の形式になり,その結果,有効桁が15桁程度になってしまうことにも注意してください.
b = 123456789012345678901234567890
c = b * 1.0
print(b)
print(c)
print(f"{c:.5f}")
123456789012345678901234567890
1.2345678901234568e+29
123456789012345677877719597056.00000
さらに,演算を繰り返すことで,その誤差は徐々に大きくなります.それでも有効桁が一気に小さくなることはないので,必要な有効桁が5桁や8桁程度であるならば恐れる必要もありません.次の例では,0.1
を 10回かけた後,10.0
を 10回かけています.さらにその操作を5回繰り返して,変数の値がどのように変化するか(数学的には一切変化しないはずですが)を確認しています.この場合,15桁目からの 5678
の箇所が,5713
, 5783
, 5836
のようになり,その誤差が徐々に大きくなっていますが,その一方で,15桁目までは変化することがなく,有効桁が15桁であることも確認できます.(この操作を何度か繰り返すと有効桁が14桁に減少することも確認すると良いでしょう.さらに繰り返したときに,有効桁が13桁,12桁・・・のようには減少しないことも同時に確認しましょう.)
b = 123456789012345678901234567890
print(b)
c = b * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 \
* 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0
print(f"{c:.5f}")
c = c * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 \
* 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0
print(f"{c:.5f}")
c = c * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 \
* 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0
print(f"{c:.5f}")
c = c * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 \
* 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0
print(f"{c:.5f}")
c = c * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 * 0.1 \
* 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0 * 10.0
print(f"{c:.5f}")
123456789012345678901234567890 123456789012345713062091685888.00000 123456789012345783430835863552.00000 123456789012345836207393996800.00000 123456789012345906576138174464.00000 123456789012345994537068396544.00000