从 .NET Framework 4.7.2 移植到 .NET5.0 后如何避免“-0”作为 double.ToString() 结果?

How to avoid "-0" as double.ToString() result after porting from .NET Framework 4.7.2 to .NET5.0?

我正在将 .NET Framework 4.7.2 Visual Studio 项目移植到 .NET5.0,当值为负且接近于零时,我遇到了 double.ToString 的不同行为。

例如,双精度值 -7.1054273576010019E-15 转换为字符串时 returns "-0" 即使我在转换前将其四舍五入,而在 .NET Framework 4.7.2 中其结果是 " 0"(相同的代码)。

这里讨论了这个区别https://devblogs.microsoft.com/dotnet/floating-point-parsing-and-formatting-improvements-in-net-core-3-0/但是我真的不同意这是标题所说的改进,我认为 0 不应该有符号,它既不是正数也不是负数数.

我知道我可以创建自定义 IFormatProvider 或扩展方法并根据需要转换 double 但这需要更改代码中的每个转换,而且任何从事该项目的开发人员都需要在未来。在我看来,这个解决方案不是很直观,很可能是错误的来源。

有没有办法更轻松地恢复以前的行为? Microsoft 是否愿意在 .NET 的未来版本中更改此设置?

编辑: 我在这里的讨论中问了同样的问题 https://github.com/dotnet/runtime/discussions/54537 如果它对其他人有帮助。

从链接 post 看来,做出更改似乎是为了更加符合 IEEE 754,这是所有语言都试图遵守的行为,以尽量减少混淆 - 或者至少标准化一种特殊形式的混淆。

如果这些更改变得过于向后不兼容并破坏了人们的程序,他们总是有可能恢复这些更改,但如果此时还没有完成(它已经在 .NET Core 3.1 中,这是LTS 版本,在 .NET 5 中)我认为不会。但是这里问“微软愿意改变这个”是错误的地方-file an issue in dotnet/runtime直接问微软

解决方法需要遍及所有地方,但也很简单:将“-0”替换为“0”。

Math.Abs 会将负零(您可以通过舍入或其他方式获得)和正零映射到 零。

因此,不用将 "-0" 替换为 "0" 作为字符串,您可以使用 Abs.

但也许你也可以这样做:

if (rounded == 0.0) {
    rounded = 0.0;  // POSITIVE zero
}

这应该将两种类型的零映射到正零。

在表达式中,可以写成 rounded == 0.0 ? 0.0 : rounded.

很清楚如何为 double 编写扩展方法,它将合并两种类型的零(并保持所有其他 double 值不变)。

相关问题在这里:

-0.1.ToString("0") is "-0" in .NET Core and "0" in .NET Framework

被标记为重复的: