C#和Java之间表达式中浮点或双精度的隐式转换/提升
如果我有以下表达式:C#和Java之间表达式中浮点或双精度的隐式转换/提升,c#,java,C#,Java,如果我有以下表达式: 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
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中是相等的。点后只有一个数字。在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)
是int
和float
的乘积,从而产生float
。这可以用C#进行模拟,如下所示:
double X2 = (float)((B * 100) + (A * D)) - (E / B) / C;
Console.WriteLine("X2: {0}", X2);
这是高级编译器的优点之一(或者有些人可能会说是缺点)。338.1在float和double中是不同的。338.1的精确二进制扩展永远重复,因此当用双精度表示时,它的非零位数比用浮点表示时多得多。请阅读