我们正在将应用程序从 .NET Framework 4.8 更新到 .NET 8。
在回归测试期间,我们注意到隐式扩展转换似乎以不同的顺序发生,导致结果发生一些变化。
在 .NET Framework 中,类似这样的操作似乎d1= f1 * f2
会先将f1
和转换f2
为双精度数,然后再执行乘法,而在 .NET 8 中,则会先进行浮点数之间的乘法,然后再进行扩展。
我知道浮点二进制数学的行为。我并不是想说其中一个是“错误的”——只是想了解为什么行为发生了变化。
并且:有没有办法将.NET 8 行为暂时改回 .NET Framework 行为,以便我们更好地理解我们的回归测试?
(PS:是的,我知道如果我们一开始没有隐式转换的话这不会是个问题。但这是一个庞大的遗留代码库,我无法轻易改变它。)
控制台应用程序测试代码:
Console.WriteLine(".NET 8");
Console.WriteLine("Input Float: 0.3333333F");
float f1 = 0.3333333F;
Console.WriteLine("Decimal: " + f1.ToString());
Console.WriteLine("Binary: " + GetFloatBinary(f1));
Console.WriteLine();
Console.WriteLine("Float multiplication first, then conversion");
Console.WriteLine("f2 = f1 * f1");
float f2 = f1 * f1;
Console.WriteLine("Decimal: " + f2.ToString());
Console.WriteLine("Binary: " + GetFloatBinary(f2));
Console.WriteLine("d1 = (double)f2");
double d1 = (double)f2;
Console.WriteLine("Decimal: " + d1.ToString());
Console.WriteLine("Binary: " + GetDoubleBinary(d1));
Console.WriteLine();
Console.WriteLine("Conversion first, multiplication second");
Console.WriteLine("d2 = (double)f1 * (double)f1");
double d2 = (double)f1 * (double)f1;
Console.WriteLine("Decimal: " + d2.ToString());
Console.WriteLine("Binary: " + GetDoubleBinary(d2));
Console.WriteLine();
Console.WriteLine("Let the platform decide");
Console.WriteLine("d3 = f1 * f1");
double d3 = f1 * f1;
Console.WriteLine("Decimal: " + d3.ToString());
Console.WriteLine("Binary: " + GetDoubleBinary(d3));
Console.WriteLine();
Console.ReadLine();
static string GetFloatBinary(float value)
{
const int bitCount = sizeof(float) * 8;
int intValue = System.BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
return Convert.ToString(intValue, 2).PadLeft(bitCount, '0');
}
static string GetDoubleBinary(double value)
{
const int bitCount = sizeof(double) * 8;
int intValue = System.BitConverter.ToInt32(BitConverter.GetBytes(value), 0);
return Convert.ToString(intValue, 2).PadLeft(bitCount, '0');
}
结果:
.NET FRAMEWORK
Input Float: 0.3333333F
Decimal: 0.3333333
Binary: 00111110101010101010101010101010
Float multiplication first, then conversion
f2 = f1 * f1
Decimal: 0.1111111
Binary: 00111101111000111000111000110111
d1 = (double)f2
Decimal: 0.111111097037792
Binary: 0000000000000000000000000000000011100000000000000000000000000000
Conversion first, multiplication second
d2 = (double)f1 * (double)f1
Decimal: 0.111111097865635
Binary: 0000000000000000000000000000000011100011100011100011100100000000
Let the platform decide
d3 = f1 * f1
Decimal: 0.111111097865635
Binary: 0000000000000000000000000000000011100011100011100011100100000000
.NET 8
Input Float: 0.3333333F
Decimal: 0.3333333
Binary: 00111110101010101010101010101010
Float multiplication first, then conversion
f2 = f1 * f1
Decimal: 0.1111111
Binary: 00111101111000111000111000110111
d1 = (double)f2
Decimal: 0.1111110970377922
Binary: 0000000000000000000000000000000011100000000000000000000000000000
Conversion first, multiplication second
d2 = (double)f1 * (double)f1
Decimal: 0.11111109786563489
Binary: 0000000000000000000000000000000011100011100011100011100100000000
Let the platform decide
d3 = f1 * f1
Decimal: 0.1111110970377922
Binary: 0000000000000000000000000000000011100000000000000000000000000000
我认为我清楚地了解了发生了什么变化,但我找不到任何关于原因的文献。
谢谢您的见解!