C# .net core 3与版本2.2产生不同的浮点结果
下面是一段示例代码,其输出来自.NETCore2.2和3.1。它显示了基本浮点表达式a^b的不同计算结果 在本例中,我们计算1.9乘以3的幂。以前的.NET框架产生了正确的结果,但是.NETCore3.0和3.1产生了不同的结果 这是一个预期的变化吗?我们如何将金融计算代码迁移到新版本,同时保证数值计算仍然会产生相同的结果?(如果.NET也有一个十进制数学库就好了) .NET核心2.2 ---十进制--------- ---双重的---------- .NET核心3.1 ---十进制--------- ---双重的----------C# .net core 3与版本2.2产生不同的浮点结果,c#,.net-core-3.1,.net-core-3.0,c#-8.0,.net-core-2.2,C#,.net Core 3.1,.net Core 3.0,C# 8.0,.net Core 2.2,下面是一段示例代码,其输出来自.NETCore2.2和3.1。它显示了基本浮点表达式a^b的不同计算结果 在本例中,我们计算1.9乘以3的幂。以前的.NET框架产生了正确的结果,但是.NETCore3.0和3.1产生了不同的结果 这是一个预期的变化吗?我们如何将金融计算代码迁移到新版本,同时保证数值计算仍然会产生相同的结果?(如果.NET也有一个十进制数学库就好了) .NET核心2.2 ---十进制--------- ---双重的---------- .NET核心3.1 ---十进制------
NET内核在IEEE浮点合规性方面引入了许多新技术。其中之一是IEEE 754-2008格式符合性 在.NET Core 3.0之前,
ToString()
在内部将精度限制为“仅”15个位置,生成的字符串无法解析回原始字符串。问题的值相差一位
在.NET 4.7和.NET Core 3中,实际字节保持不变。在这两种情况下
BitConverter.GetBytes(d*d*d)
产生
85, 14, 45, 178, 157, 111, 27, 64
另一方面,BitConverter.GetBytes(6.859)
产生:
86, 14, 45, 178, 157, 111, 27, 64
即使在.NET Core 3中,解析“6.859”也会生成第二个字节序列:
BitConverter.GetBytes(double.Parse("6.859"))
这是一个单位差异。旧行为生成的字符串无法解析回原始值
这种变化解释了这种差异:
ToString()、ToString(“G”)和ToString(“R”)现在将返回最短的可循环字符串。这可以确保用户最终得到默认情况下可以正常工作的东西
这就是为什么我们在处理浮点数时总是需要指定精度。在这种情况下也有改进:
对于采用精度的“G”格式说明符(例如G3),现在始终遵守精度说明符。对于精度小于15(含15)的double和精度小于6(含6)的float,这意味着您将获得与之前相同的字符串。对于大于该值的精度,您将得到许多有效数字
使用ToString(“G15”)
生成6.859
,而ToString(“G16”)
生成6.85899999999999
,它有16个小数位数
这提醒我们,在处理浮点数时,无论是比较还是格式化,我们都需要指定一个精度。在.NET Core 3.1中有很多有记录的浮点数改进。请让这个问题更具可读性。原始值和预期值是什么?为什么预期值被认为是正确的?旧结果有一点错误。实际的双精度值是相同的,但旧的字符串格式化程序生成了一个以单个位“是”关闭的字符串。1.9^3正好是6.859。被接受的答案以及例子和链接帮助我解决了这个问题。
a * a * a = 6.858999999999999
Math.Pow(a, b) = 6.858999999999999
BitConverter.GetBytes(d*d*d)
85, 14, 45, 178, 157, 111, 27, 64
86, 14, 45, 178, 157, 111, 27, 64
BitConverter.GetBytes(double.Parse("6.859"))