C#からJavaに触れてつまづきそうになること – Challenge Java EE !.
上のサイトにある、doubleの処理。
doubleの計算
C#
Console.WriteLine(2.00 – 1.10);0.9
Java
System.out.println(2.00 – 1.10);0.8999999999999999
そんな馬鹿な!!
IEEE 754的には0.9という答えは実際にはおかしいということは皆さん理解していると思います。実際のところどうなのって言うことで、自分でもコードを書いて見ました。(本当に0.9って計算されていたらヤヴァイ)
using System;
namespace CsDoubleCalc
{
class Program
{
static void Main(string[] args) {
Console.WriteLine(2.0 - 1.1);
Console.Read();
}
}
}
結果:
> 0.9
うーん。ということで、ILDASMでILを見てみます。
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// コード サイズ 23 (0x17)
.maxstack 8
IL_0000: nop
IL_0001: ldc.r8 0.89999999999999991
IL_000a: call void [mscorlib]System.Console::WriteLine(float64)
IL_000f: nop
IL_0010: call int32 [mscorlib]System.Console::Read()
IL_0015: pop
IL_0016: ret
} // end of method Program::Main
そもそも実際には計算してないで、コンパイルが計算結果をリテラルとして埋め込んでいるわけですが、ただ内部的にはIEEE 754通り計算していそうなことはわかったと思います。
つまり、計算結果に違いがあると言うより、.NET Frameworkコンソール出力ライブラリ(System.Console)が、人間的に文句が出ない方向で値をまるめているって言うのが正解だと思います。(それはそれでいいのかっていうのもあるけど・・・)
これで一安心です。
コメント
それで出力は同じなのに比較がFalseになってすごい悩んだことがありました。
ConsoleというかToString()の標準のフォーマットだと丸められてしまうせいで、ToString(“R”)という風にラウンドトリップ指定するとちゃんと戻りますね。
Kazutada Ito liked this on Facebook.
Kazushi Kamegawa liked this on Facebook.
Kiyokazu Kaba liked this on Facebook.
記事のフォローありがとうございます。
浮動小数点は統合で比較しちゃダメとか、基本的な部分が最近はまり共有できていないと思ったりすることが最近多いですね。
Double型の書式設定(.ToString(string format))の挙動が原因であるようです。
上記例であればConsole.WriteLine(“{0:G17}”, 2.0 – 1.1);とすると以下の出力となりました。
0.89999999999999991
デフォルトの書式文字列は”G”であるために勝手に丸められてしまうようですね。
同趣旨のコメントついてるのに気づきませんでした。申し訳ないです。