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

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

kumaGoro95
April 26, 2021
150

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

kumaGoro95

April 26, 2021
Tweet

More Decks by kumaGoro95

Transcript

  1. プログラミングで小数計算すると

    なんで誤差が発生するのか?

    くまごろー

    ?


    View full-size slide

  2. このテーマを選んだいきさつ

    ● プログラミング学習を進めてると、「double/float型で小数計算すると誤差が
    発生する」という現象に遭遇する

    ● 参考書では「正確に計算したいときはBigDecimal型を使いましょう」とか言
    われる


    問1 そもそも、プログラミングで小数計算するとなんで誤差が発生するの?

    問2 なんでBigDecimal型で計算すると誤差が発生しないの?


    View full-size slide

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


    View full-size slide

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

    double num1 = 1.2;
    double num2 = 1.0;
    System.out.println(num1 - num2);
    //0.19999999999999996

    View full-size slide

  5. なぜこうなるのか?

    Q

    A
 コンピュータは2進数で計算している

    View full-size slide

  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 になる


    View full-size slide

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

    1
 1
 1
 .
 1
 1
 1
 1

    100
 10
 1
 
 1/10
 1/100
 1/1000
 1/10000

    〇「111.1111」という数字があるとする

    これが10進数表記だったら・・・

    <各桁の重み>


    View full-size slide

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

    View full-size slide

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


    View full-size slide

  10. ケース1:循環小数 

    double num1 = 1.2;
    double num2 = 1.0;
    System.out.println(num1 - num2);
    //0.19999999999999996

    → 「0.2」は2進数で表せない
     (2進数だと「0.001100110011...」循環小数に)

    View full-size slide

  11. double num1 = 0.1234;
    double num2 = 0.000000000000000004321;
    System.out.println(num1 + num2);
    //0.1234
    ケース2:情報落ち 

    → double/float型は浮動小数点数(桁数が有限)なので、

     正規化が行われる(切り捨てられる)


    View full-size slide

  12. 浮動小数点数とは

    ↓のような指数表記で小数を表記する方法。

    例:2進数の-0.0001の場合(10進数だと0.0625)

    -
    -3

    - 0.1 × 2

    符号

    仮数
 指数

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


    View full-size slide

  13. 浮動小数点数とは

    
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

    -
    - 3

    - 0.1 × 2

    符号

    仮数
 指数

    符号
    (1Bit)

    指数
    (11Bit)

    仮数
    (52Bit)

    〇 double型(64ビット)の場合

    → 仮数が52ビット以上だと、切り捨てられる


    View full-size slide

  14. 3
    なんでBigDecimalを使うと

    誤差が生じないの?


    View full-size slide

  15. ● 「整数×10のマイナス乗」という式で数値を表現
    BigDecimalの仕組み

    BigDecimalは、次のように値を保持している

    -scale
    unscaledValue×10
    ●  整数は小数と違い、2進数でも(何進数でも)全ての数値を表す
    ことができる。

    10進数「1.2」の場合... 

    -1 

    





    12 × 10


    View full-size slide

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


    View full-size slide