gpt4 book ai didi

c# - .net core 3 产生与 2.2 版本不同的浮点结果

转载 作者:行者123 更新时间:2023-12-04 00:02:00 25 4
gpt4 key购买 nike

这是一段示例代码,其输出来自 .net core 2.2 和 3.1。它显示了基本浮点表达式 a^b 的不同计算结果。

在本例中,我们计算 1.9 的 3 次方。以前的 .NET 框架产生正确的结果,但 .net core 3.0 和 3.1 产生不同的结果。

这是有意更改吗?我们如何将财务计算代码迁移到新版本,同时保证数值计算仍会产生相同的结果? (如果 .NET 也有十进制数学库就好了)。

    public static class Program
{
public static void Main(string[] args)
{
Console.WriteLine("--- Decimal ---------");
ComputeWithDecimalType();
Console.WriteLine("--- Double ----------");
ComputeWithDoubleType();

Console.ReadLine();
}

private static void ComputeWithDecimalType()
{
decimal a = 1.9M;
decimal b = 3M;
decimal c = a * a * a;
decimal d = (decimal) Math.Pow((double) a, (double) b);

Console.WriteLine($"a * a * a = {c}");
Console.WriteLine($"Math.Pow((double) a, (double) b) = {d}");
}

private static void ComputeWithDoubleType()
{
double a = 1.9;
double b = 3;
double c = a * a * a;
double d = Math.Pow(a, b);

Console.WriteLine($"a * a * a = {c}");
Console.WriteLine($"Math.Pow(a, b) = {d}");
}
}

.NET 核心 2.2

--- 十进制 ---------
a * a * a                        = 6.859
Math.Pow((double) a, (double) b) = 6.859

- - 双倍的 - - - - -
a * a * a      = 6.859
Math.Pow(a, b) = 6.859

.NET 核心 3.1

--- 十进制 ---------
a * a * a                        = 6.859
Math.Pow((double) a, (double) b) = 6.859

- - 双倍的 - - - - -
a * a * a      = 6.858999999999999
Math.Pow(a, b) = 6.858999999999999

最佳答案

.NET Core 引入了很多 floating point parsing and formatting improvements在 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"), and ToString("R") will now return the shortest roundtrippable string. This ensures that users end up with something that just works by default.



这就是为什么我们在处理浮点数时总是需要指定精度的原因。在这种情况下也有改进:

For the "G" format specifier that takes a precision (e.g. G3), the precision specifier is now always respected. For double with precisions less than 15 (inclusive) and for float with precisions less than 6 (inclusive) this means you get the same string as before. For precisions greater than that, you will get up to that many significant digits



使用 ToString("G15")生产 6.859ToString("G16")生产 6.858999999999999 , 有 16 个小数位。

这提醒我们在处理浮点数时我们总是需要指定精度,无论是比较还是格式化

关于c# - .net core 3 产生与 2.2 版本不同的浮点结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59781786/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com