如果我有以下表达式:
byte A = 69;
int B = 123;
long C = 3210;
float D = 4.9f;
double E = 11.11;
double X = (B * 100) + 338.1 - (E / B) / C;
double X1 = (B * 100) + (A * D) - (E / B) / C;
// JAVA - lost precision
System.out.println(X); // 12638.099971861307
System.out.println(X1); // 12638.099581236307
// C# - almost the same
Console.WriteLine(X); // 12638.0999718613
Console.WriteLine(X1) // 12638.0999784417
我注意到Java从X中失去了精度,其中338.1是隐式的两倍,而C#几乎没有。我不明白为什么因为338.1在float和double中是等于的。点后只有一位数。
答案 0 :(得分:1)
在Java中,(B * 100) + (A * D)
将是一个浮点数;它将是最接近12638.1的浮点数。但是,12638需要14位数字以二进制表示,包括初始1;留下有效数字的10位数来表示小数部分。因此,您将获得最接近的1024次数到0.1 - 即102/1024。结果是0.099609375 - 因此浮点数的舍入误差为0.000390625。
这似乎是你在Java程序中得到的X和X1之间的区别。
我担心我不是C#专家,所以我不能告诉你为什么C#不同。
答案 1 :(得分:0)
这与你的表达式的编译器解释有关。由于您尚未指定任何中间类型转换,编译器将执行A * D
作为第一类型转换,然后执行乘法,而不是您期望的反向。这可能看起来像一个奇怪的结果,但它是编译器为您提供更精确结果的一种方式,而无需指定繁琐的类型转换。
Java不会为您处理此问题,因此(B * 100) + (A * D)
是int
和float
的乘法 - 导致float
。这可以在C#中模拟如下:
double X2 = (float)((B * 100) + (A * D)) - (E / B) / C;
Console.WriteLine("X2: {0}", X2);
这是高级编译器的优点之一(或者有些人可能会说不利)。