この例では、実際には微妙に異なることがいくつかあります。
float を小数点以下 6 桁に丸めようとしています。double から float への変換は、ほとんどこれを行うようです
丸める必要がある場合は、Roundメソッドを使用します。変換すると精度が失われる可能性があり、浮動小数点型はそもそも無限に正確ではありません。
最後に余分な数字が表示されるのはなぜですか?
内部的に float と double は、 IEEE 754標準に従ってバイナリで表されます。あなたの数字 50.8467178 は、1/3 を 10 進数で (数字を繰り返さずに) 正確に表すことができないのと同じように、2 進数で正確に表すことはできません。標準では、float としての数値は として格納され0x424B6304
ます。これは、24 ビットまたは 6 ~ 9 桁の 10 進数まで正確です。ここで、標準に従ってその数値を再解釈すると、次のようになります。
0x424B6304
= 1.58895993232727 * 2^5
= 50.84671783447264
デバッガーであろうとToString()
メソッドの呼び出しであろうと、ディスプレイは、最初の 6 ~ 9 桁のみが重要であることを認識できるほどスマートです (これは、IEEE 標準と一致しています)。最大 9 桁を取ると、float は のように表示され50.8467178
ます。
ただし、この数値を double に変換しても、バイナリ値は変わりません。その内部ビット パターンは確かにそうですが、2 進数は依然として として解釈され1.58895993232727 * 2^5
ます。問題は、double が 53 ビット、つまり 10 進数で 15 ~ 17 桁まで正確であることです。そのため、表示されると、元の 6 ~ 9 桁ではなく、15 ~ 17 桁が表示されます。したがって、倍精度に変換されたときに余分な数字があるわけではなく、数字はすでにそこにありました。
中間の float 変換がない場合、double を使用して 50.8467178 をより正確に表すことができます。として保存され0x40496C613FB5F875
ます。これについてはまだ計算していませんが、上記の手順を使用すると、次のような結果が得られます50.84671780000000000000000000023155
。最初の 15 ~ 17 桁のみを考慮すると、ディスプレイに表示されるのは 50.8467178 になります (有効な 0 は省略されています)。
どうすればこれを止めることができますか?
float にキャストして丸めないでください。正確な数字は 6 ~ 9 桁しかありません。通常、10 進数型は 10 進数の精度が必要な場合に適していますが、コードのその部分を変更することはできないため、このRound
メソッドを使用することはアプリケーションにとって十分な精度である必要があります (1,000,000,000 未満である限り)。
上記のいずれかで ToString() を呼び出すと、デバッガーが表示するものとは異なる小数点以下の桁数が出力されることが多いのはなぜですか?
私はこの問題を回避して、物事を単純かつ連続的に保つように努めてきました。精度の範囲を 10 進数で指定しています。浮動小数点数の場合は 6 ~ 9、倍精度浮動小数点数の場合は 15 ~ 17 です。double を例にとると、このToString()
メソッドはデフォルトで 10 進数 15 桁の文字列を返します。ToString("G17")
ただし、 (doc)を呼び出して 17 桁の 10 進数を返すように強制することはできますが、これらの 2 桁が有効であるという保証はありません。デバッガーが表示のためにこのバージョンを呼び出していると思われます。これが と異なる理由ToString()
です。
詳細な資料: IEEE 算術、Oracle による。かなりテクニカルですが。