浮動小数点型の誤差 double float IEEE754 - 萌えJava超入門
第五章 演算子

浮動小数点型の誤差

double と、float は、小数点以下の値で誤差が出ることがあります。
プログラミングにおいて「浮動小数点型の誤差」は基本なのです。


小数のための
データ型なのに?!
目次


1.double と、float は、小数点が苦手


ホントに苦手なんです。
見てやってください。

//Sample04_01.java
class Sample04_01 {
    public static void main(String[] args){
        System.out.println(0.1 + 0.2);
        System.out.println(0.3 * 3);
        System.out.println(0.42 / 3);
        System.out.println(0.6 + 0.7);
        System.out.println(0.67 * 3);
        System.out.println(0.8 - 0.1);
        System.out.println(12742 * 3.14);
    }
}

コマンドライン
> javac Sample04_01.java
> java Sample04_01
0.30000000000000004
0.8999999999999999
0.13999999999999999
1.2999999999999998
2.0100000000000002
0.7000000000000001
40009.880000000005

ざっとこんなもんだ。



これはひどい...。



そんなに複雑な計算じゃ
ないっすよね?!
まあ誰にでも苦手なものは
あるものだよ。



ちょ、ちょっと!
それで済ますつもり?
小数を扱えるのは
double と floatしかないっスよ?


2. 10進数の少数は2進数で表現しにくい


先ずは言い訳から。
コンピュータの中では、値を2進数で処理しています。
double や、floatも、
10進数のリテラル → 2進数で処理 → 10進数で表示 と処理されます。

整数は、10進数で表現できたものを2進数で表すことに問題ありませんが、
小数点以下の値は、たとえ10進数で表現できたとしても、2進数では循環小数になりやすいのです。

循環小数になると、表現可能な範囲をもって切り捨てられるので、
その分が誤差になるのです。

10進数の少数は2進数で表現しにくい
10進数2進数コメント
0.10.000110011...循環小数
0.20.001100110...循環小数
0.30.001110011...循環小数
0.40.011001100...循環小数
0.50.1誤差なし
0.60.100110011...循環小数
0.70.101100110...循環小数
0.80.110011001...循環小数
0.90.111001100...循環小数
11誤差なし
0.250.01誤差なし
0.750.11誤差なし
0.1250.001誤差なし
見ての通り
0.1~0.9 の9箇所で、
2進数で表現しきれたのは
0.5の1コだけだ。

1を2で割り続けた値や、それらの和になっている小数は2進数で表現できます。
とはいえ、10進数と2進数は相性があまりいいとは言えないですね。



3. 浮動小数点算術に関する標準IEEE754


プログラムが浮動小数点型の数値を2進数で扱っているために発生してしまう誤差は、
Javaに限らず多くの言語で発生します。

プログラミングにおいて「浮動小数点型の誤差」は基本なのです。

IEEE標準で定められたメジャーな標準だというのですから仕方ありませんね。(IEEE754)
誤差の値自体はとても小さな値なので「適切な桁で四捨五入して使ってね。」
という感じです。

なお、Javaには「BigDecimal」というクラスが用意されているので、 正確な計算を求める場合にはこちらを使用するのが一般的です。

見逃して。


お疲れ様でした。




© 2019 awasekagami