Slide 1

Slide 1 text

プログラミングで小数計算すると
 なんで誤差が発生するのか?
 くまごろー
 ?


Slide 2

Slide 2 text

このテーマを選んだいきさつ
 ● プログラミング学習を進めてると、「double/float型で小数計算すると誤差が 発生する」という現象に遭遇する
 ● 参考書では「正確に計算したいときはBigDecimal型を使いましょう」とか言 われる
 
 問1 そもそも、プログラミングで小数計算するとなんで誤差が発生するの?
 問2 なんでBigDecimal型で計算すると誤差が発生しないの?


Slide 3

Slide 3 text

1 誤差が出るってどういうこと?


Slide 4

Slide 4 text

double/float型で計算すると → 答えは「0.2」のはずなのに、誤差が生じる
 double num1 = 1.2; double num2 = 1.0; System.out.println(num1 - num2); //0.19999999999999996 


Slide 5

Slide 5 text

なぜこうなるのか?
 Q
 A
 コンピュータは2進数で計算している

Slide 6

Slide 6 text

● 「0」と「1」という2個の数字を使って数を表す
 ● その桁の数値が「2」になると桁上がりする
 2進数って?
 10進数
 2進数
 1
 1
 2
 10
 3
 11
 4
 100
 4桁目
 3桁目
 2桁目
 1桁目
 8
 4
 2
 1
 例:2進数の「1111」を
      10進数に直すと...
 → 8+4+2+1 = 15 になる


Slide 7

Slide 7 text

2進数での小数の表し方
 1
 1
 1
 .
 1
 1
 1
 1
 100
 10
 1
 
 1/10
 1/100
 1/1000
 1/10000
 〇「111.1111」という数字があるとする
 これが10進数表記だったら・・・
 <各桁の重み>


Slide 8

Slide 8 text

2進数での小数の表し方
 1
 1
 1
 .
 1
 1
 1
 1
 4
 2
 1
 
 1/2
 1/4
 1/8
 1/16
 〇「111.1111」という数字があるとする
 では、2進数だったら?
 2進数の「111.1111」を10進数に直すと
 → (4+2+1) + (0.5 + 0.25 + 0.125 + 0.0625) = 7.9375 
 2の倍数の分母を持つ分数でないと表せない 


Slide 9

Slide 9 text

2 誤差はどのように発生しているのか


Slide 10

Slide 10 text

ケース1:循環小数 
 double num1 = 1.2; double num2 = 1.0; System.out.println(num1 - num2); //0.19999999999999996 
 → 「0.2」は2進数で表せない  (2進数だと「0.001100110011...」循環小数に)

Slide 11

Slide 11 text

double num1 = 0.1234; double num2 = 0.000000000000000004321; System.out.println(num1 + num2); //0.1234 ケース2:情報落ち 
 → double/float型は浮動小数点数(桁数が有限)なので、
  正規化が行われる(切り捨てられる)


Slide 12

Slide 12 text

浮動小数点数とは
 ↓のような指数表記で小数を表記する方法。
 例:2進数の-0.0001の場合(10進数だと0.0625)
 - -3
 - 0.1 × 2
 符号
 仮数
 指数
 → 表記できる桁数が増える


Slide 13

Slide 13 text

浮動小数点数とは
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 - - 3
 - 0.1 × 2
 符号
 仮数
 指数
 符号 (1Bit)
 指数 (11Bit)
 仮数 (52Bit)
 〇 double型(64ビット)の場合
 → 仮数が52ビット以上だと、切り捨てられる


Slide 14

Slide 14 text

3 なんでBigDecimalを使うと
 誤差が生じないの?


Slide 15

Slide 15 text

● 「整数×10のマイナス乗」という式で数値を表現 BigDecimalの仕組み
 BigDecimalは、次のように値を保持している
 -scale unscaledValue×10 ●  整数は小数と違い、2進数でも(何進数でも)全ての数値を表す ことができる。
 10進数「1.2」の場合... 
 -1 
 




 12 × 10


Slide 16

Slide 16 text

ご清聴ありがとうございました