double 同士の演算結果が異なるのはなぜでしょうか？


下記画像のように計算すると結果に誤差が発生します。  
これは倍精度浮動小数誤差が発生している結果という認識です。

[![画像の説明をここに入力](https://i.stack.imgur.com/1AMNW.png)](https://i.stack.imgur.com/1AMNW.png)

  1. しかし、 **22.15** ではなく、 **22.14** では誤差が発生しません。

[![画像の説明をここに入力](https://i.stack.imgur.com/8c6Mq.png)](https://i.stack.imgur.com/8c6Mq.png)

  2. さらに **2400** * 22.15でも誤差が発生しません。

[![画像の説明をここに入力](https://i.stack.imgur.com/8x0J8.png)](https://i.stack.imgur.com/8x0J8.png)

### 質問

なぜ1と2は誤差が発生していないのでしょうか？



[code]

    var value1 = 2600 * 22.15d;
    var value2 = 2600 * 22.14d;
    var value3 = 2400 * 22.15d;
    
[/code]

というコードは（デバッグビルドであろうと）コンパイル時に定数式が計算されていて

[code]

    var value1 = 57589.999999999993;
    var value2 = 57564.;
    var value3 = 53160.;
    
[/code]

というコードが生成されています。コンパイラーが誤差を埋め込んでしまった形です。

* * *

[`BitConverter.DoubleToInt64Bits`](https://docs.microsoft.com/en-
us/dotnet/api/system.bitconverter.doubletoint64bits?view=net-5.0)を使用すると`double`の値がどのようなビットパターンで格納されているかを見ることができます。また、`String.Format`等では表示する精度を指定できます。

[code]

    using System;
    static void Print(double x) =>
        Console.WriteLine("{0:X16} / {1:F10} / {1:F11} / {1:F30}", BitConverter.DoubleToInt64Bits(x), x);
    Print(2600 * 22.15d);
    Print(2600 * 22.14d);
    Print(2400 * 22.15d);
    
[/code]

を実行すると

[code]

    40EC1EBFFFFFFFFF / 57590.0000000000 / 57589.99999999999 / 57589.999999999992724042385816574097
    40EC1B8000000000 / 57564.0000000000 / 57564.00000000000 / 57564.000000000000000000000000000000
    40E9F50000000000 / 53160.0000000000 / 53160.00000000000 / 53160.000000000000000000000000000000
    
[/code]

となっていて、表示する桁数によって切り上げられるか切り下げられるかの違いが生じます。



[code]

    var value1 = 2600 * 22.15d;
    var value2 = 2600 * 22.14d;
    var value3 = 2400 * 22.15d;
    
[/code]

というコードは（デバッグビルドであろうと）コンパイル時に定数式が計算されていて

[code]

    var value1 = 57589.999999999993;
    var value2 = 57564.;
    var value3 = 53160.;
    
[/code]

というコードが生成されています。コンパイラーが誤差を埋め込んでしまった形です。

* * *

[`BitConverter.DoubleToInt64Bits`](https://docs.microsoft.com/en-
us/dotnet/api/system.bitconverter.doubletoint64bits?view=net-5.0)を使用すると`double`の値がどのようなビットパターンで格納されているかを見ることができます。また、`String.Format`等では表示する精度を指定できます。

[code]

    using System;
    static void Print(double x) =>
        Console.WriteLine("{0:X16} / {1:F10} / {1:F11} / {1:F30}", BitConverter.DoubleToInt64Bits(x), x);
    Print(2600 * 22.15d);
    Print(2600 * 22.14d);
    Print(2400 * 22.15d);
    
[/code]

を実行すると

[code]

    40EC1EBFFFFFFFFF / 57590.0000000000 / 57589.99999999999 / 57589.999999999992724042385816574097
    40EC1B8000000000 / 57564.0000000000 / 57564.00000000000 / 57564.000000000000000000000000000000
    40E9F50000000000 / 53160.0000000000 / 53160.00000000000 / 53160.000000000000000000000000000000
    
[/code]

となっていて、表示する桁数によって切り上げられるか切り下げられるかの違いが生じます。

