はじめに
- 筆者が疑問に思って検証した結果を書いたもので、double型のすべてを記したものではない
- この記事内の「出力」というのは、Console.WriteLineの表示結果のこと
- 「16進数出力」は、BitConverter.DoubleToInt64Bits()を使用して、doubleのビットの状態を表示したもの
各種定数のビット
| 定数 | 16進数出力 |
|---|---|
| 0 | 0x0000000000000000 |
| 1 | 0x3FF0000000000000 |
| MinValue | 0xFFEFFFFFFFFFFFFF |
| MaxValue | 0x7FEFFFFFFFFFFFFF |
| Epsilon | 0x0000000000000001 |
| NaN | 0xFFF8000000000000 |
0.99… どのくらいまでなら正確に保持できるか
結論
- コード上で表記:0.9999999999999999
- 16進数の場合:0x3FEFFFFFFFFFFFFF
検証:コード上で直接入力して出力した結果
- 9の数が17以上になると、1.0となってしまう。
- 0x3FEFFFFFFFFFFFFFは、1.0 未満だが、出力すると 1.0 となる。
| 9の数 | コード上の表記 | 10進数出力 | 16進数出力 |
|---|---|---|---|
| 1 | 0.9 | 0.9 | 0x3FECCCCCCCCCCCCD |
| 2 | 0.99 | 0.99 | 0x3FEFAE147AE147AE |
| 略 | |||
| 15 | 0.999999999999999 | 0.999999999999999 | 0x3FEFFFFFFFFFFFF7 |
| 16 | 0.9999999999999999 | 1.0 | 0x3FEFFFFFFFFFFFFF |
| 17 | 0.99999999999999999 | 1.0 | 0x3FF0000000000000 |
| 18 | 0.999999999999999999 | 1.0 | 0x3FF0000000000000 |
検証:1.0から徐々に小さくしていった場合
- BitConverter.Int64BitsToDouble()を使用して、整数から実数に変換し出力
- 0x3FEFFFFFFFFFFFFFは、1.0 未満だが、出力すると 1.0 となる。
| 元の整数 | 実数出力 |
|---|---|
| 0x3FF0000000000000 | 1.0 |
| 0x3FEFFFFFFFFFFFFF | 1.0 |
| 0x3FEFFFFFFFFFFFFE | 1.0 |
| 0x3FEFFFFFFFFFFFFD | 1.0 |
| 0x3FEFFFFFFFFFFFFC | 1.0 |
| 0x3FEFFFFFFFFFFFFB | 0.999999999999999 |
| 0x3FEFFFFFFFFFFFFA | 0.999999999999999 |
doubleで正確に保持可能な整数の最大値
結論
- 9007199254740992
- 16進数:0x20000000000000
検証:long→double→longの順番でキャスト
- 0x20000000000001 は、longに戻した後 0x20000000000000 になってしまう。
各出力結果
| 元のlong値 | 代入後のdouble値(16進数出力) | キャスト後のlong値 |
|---|---|---|
| 0x1FFFFFFFFFFFFF | 0x433FFFFFFFFFFFFF | 0x1FFFFFFFFFFFFF |
| 0x20000000000000 | 0x4340000000000000 | 0x20000000000000 |
| 0x20000000000001 | 0x4340000000000000 | 0x20000000000000 |
ToStringのフォーマット
double.Epsilon を小数表記で出力する方法
結論:桁プレースホルダーを使用する
"0.####・・・"の、"#"が338個並んだフォーマットを使用する。
検証:書式指定子を使用した場合
- 小数表記で表示されず、指数表記になる。
- 精度指定子では99桁が限界、100桁以上は"F100"のように出力されてしまう。
- 補足:C,E,Pは、そもそも目的が違うので、ここには載せていません。
| 書式指定子 | 出力結果 |
|---|---|
| F99 | 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 |
| G99 | 4.9406564584124654E-324 |
| N99 | 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 |
| R99 | 4.94065645841247E-324 |
検証:桁プレースホルダーを使用した場合
- 桁プレースホルダーとは、"0.####"のように書いたフォーマットのこと
| #の数 | 出力結果 |
|---|---|
| 337 | 0.000(略)00049406564584125 |
| 338 | 0.000(略)000494065645841247 |
| 339 | 0.000(略)000494065645841247 |