7

如果我有以下表达式:

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 等于浮点数和双精度数。点后只有一位数字。

4

2 回答 2

1

在 Java 中,(B * 100) + (A * D)将是一个浮点数;它将是最接近 12638.1 的浮点数。但是12638需要14位二进制表示,包括开头的1;它留下 10 位有效数字来表示小数部分。因此,您将获得最接近 0.1 的 1024 分之一 - 即 102/1024。结果是 0.099609375 - 所以浮点数的舍入误差为 0.000390625。

这似乎是您在 Java 程序中获得的 X 和 X1 之间的区别。

恐怕我不是 C# 专家,所以我不能告诉你为什么 C# 不同。

于 2013-10-17T10:23:33.923 回答
0

这与编译器对表达式的解释有关。由于您没有指定任何中间类型转换,因此编译器执行第A * D一个类型转换,然后执行乘法,而不是您期望的相反。这可能看起来像一个奇怪的结果,但它是编译器为您提供更准确结果的一种方式,您无需指定繁琐的类型转换。

Java 不会为您处理这个问题,因此a 和 a(B * 100) + (A * D)的乘法- 得到 a 。这可以在 C# 中像这样模拟:intfloatfloat

double X2 = (float)((B * 100) + (A * D)) - (E / B) / C;
Console.WriteLine("X2: {0}", X2);

这是高级编译器的优点之一(或者有些人可能会说的缺点)。

于 2013-10-17T11:24:08.370 回答