Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

kumaGoro95
April 26, 2021
93

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

kumaGoro95

April 26, 2021
Tweet

Transcript

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


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


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


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

    System.out.println(num1 - num2); //0.19999999999999996 

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

  6. • 「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 になる

  7. 2進数での小数の表し方
 1
 1
 1
 .
 1
 1
 1
 1
 100


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

  8. 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の倍数の分母を持つ分数でないと表せない 

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


  10. ケース1:循環小数 
 double num1 = 1.2; double num2 = 1.0;

    System.out.println(num1 - num2); //0.19999999999999996 
 → 「0.2」は2進数で表せない  (2進数だと「0.001100110011...」循環小数に)
  11. double num1 = 0.1234; double num2 = 0.000000000000000004321; System.out.println(num1 +

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

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


    仮数
 指数
 → 表記できる桁数が増える

  13. 浮動小数点数とは
 
 
 
 
 
 
 
 
 


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

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


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

    
 -1 
 




 12 × 10

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