【发布时间】:2020-11-18 17:23:05
【问题描述】:
我正在将一个应用程序从 .NET Framework 4.6.2 迁移到 .NET Core 3.1,但我的单元测试在我没想到的地方失败了。
经过一些计算,我最终得到了一个 16 位的double。根据调试器,无论我运行.NET462 还是.NETCore31 代码,我都得到了完全相同的值。当我“序列化”这个值时,就会出现差异。在.NETCore31 版本中,最后一位丢失了:
这是一个例子:
.NET
4.0584789241077042.ToString("R", CultureInfo.InvariantCulture)
// "4.0584789241077042" (the exact same number)
.NET 核心
4.0584789241077042.ToString("R", CultureInfo.InvariantCulture);
// "4.058478924107704" (the last digit is gone)
这实际上不是问题,我的计算不需要这么精确,但是有人知道为什么我会得到两个不同的结果吗?
【问题讨论】:
-
.NET Core 大大改进了浮点数。查看接受的答案here,因为我认为它会回答您的问题
-
我不确定链接的答案是否回答了这个问题——这个问题的位数在较新版本的 .NET Core 上递减
-
@canton7 但您提供的“答案”链接到同一篇文章并引用了文章的相同部分......
-
@AlexeiLevenkov 我确实使用了相同的来源,但该答案集中在 .NET Core 3.0 之前的版本上,生成无法往返的字符串。这个问题不是这样,
ToString("R")的结果可以在 .NET Core 3.0 之前很好地进行往返。虽然其他答案确实引用了“ToString("R") 现在将返回最短的可往返字符串”,但它没有解释这如何适用于 OP 的问题。通过显示"4.058478924107704"被解析回4.0584789241077042,我尝试进一步扩展“最短的可往返字符串” -
自 2019 年 2 月以来,CoreCLR 发生了重大变化。它曾经在 CLR 中使用 C++ 实现,使用 15 或 17 位有效数字。现在用 C# 编写,通过 Grisu 算法产生最短的可能。