C# 和 Java 之间表达式中浮点数或双精度型的隐式转换/提升

本文关键字:转换 提升 双精度型 Java 之间 表达式 浮点数 | 更新日期: 2023-09-27 18:35:41

如果我有以下表达式:

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 在浮点数和双精度数上相等。点后只有一个数字。

C# 和 Java 之间表达式中浮点数或双精度型的隐式转换/提升

在 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# 与众不同。

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

Java 不会为您处理这个问题,因此(B * 100) + (A * D)intfloat的乘法 - 导致float。这可以在 C# 中模拟,如下所示:

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

这是高级编译器的优点(或缺点)之一。