深入探讨 .NET Core 3.0 浮点计算差异与解决方案
在 .NET Core 3.0 中,对浮点解析和格式进行了更改,以符合 IEEE 754-2008 标准。您可以在这篇文章中阅读有关这些更改的更多信息。在使用 Stimulsoft 产品时,这些更改最常表现为舍入数字和出现“负号”零。
Stimulsoft Ultimate (原Stimulsoft Reports.Ultimate)是用于创建报表和仪表板的通用工具集。该产品包括用于WinForms、ASP.NET、.NET Core、JavaScript、WPF、PHP、Java和其他环境的完整工具集。无需比较产品功能,Stimulsoft Ultimate包含了所有内容!
Stimulsoft Reports 最新下载
负零
负号零和正号零在数学分析中用作负无穷小量和正无穷小量的常规符号。在典型的编程任务中,常规零就足够了,但一些高级数学计算需要这些区别。为了解决这个问题,引入了“负号零”。
负零是四舍五入负数的结果。例如,以前,Math.Round(-0.01, 0)的结果为“0”,但现在为“-0”。在格式化数字(数字、货币、百分比格式)时也会出现这种情况,因为在格式化过程中使用了四舍五入。从数学上讲,这种方法更准确。然而,从编程的角度来看,这被认为是一个“重大变化”,因为四舍五入操作的标准行为已经改变,并且没有直接的方法来禁用这种修改。
为了解决出现负零的问题,我们修改了 .NET Core 系列产品,默认情况下,负号零被替换为常规零。但是,如果您的计算仍然需要负零,则可以通过设置StiOptions.Engine.AllowNegativeZero = true选项来启用它。
数字四舍五入
.NET Core 3.0 中的一项改进涉及对浮点数语法分析的更改。这种改进的原因在于数字在 float 和 double 类型中的存储方式。这些数字以二进制形式存储,仅在四舍五入或显示在屏幕上时转换为十进制。例如,数字“0.0045”实际上以“0.00449999999999999996”之类的形式存储在内存中。然后,在显示时,一种特殊的方法会从此二进制表示形式“恢复”原始数字。因此,不可能用 float 和 double 类型精确表示十进制数 - 它们总是会包含一定程度的误差。以前
,这些数字转换的算法与 IEEE 754-2008 标准中指定的算法不同,这导致不同系统上的计算结果不同。现在,随着 .NET Core 3.0 中的更新,计算结果符合标准。但是,与早期版本相比,这可能会导致不同的结果,这也会影响标准 Round 函数,可能产生与以前不同的结果。
这给一些同时维护 .NET Framework 和 .NET Core 版本产品的客户带来了问题,因为他们现在看到两个版本的结果不同。请注意!
为确保计算结果在不同环境中一致且可预测,我们建议使用以下方法:在所有关键计算中,将类型转换为十进制。这将保证准确的舍入并最大限度地减少任何计算中的错误。修改多个报告很容易,但有些用户遇到需要重新制作许多以前创建的报告的情况。针对这种情况,我们添加了一个新选项:
StiOptions.Engine.ForceConversionToDecimalInTextFormat = false;
默认情况下,此选项处于禁用状态。如果将其设置为 true,则在以“数字”、“货币”和“百分比”格式格式化文本时,浮点数和双精度参数将自动转换为十进制,以提高舍入精度。
MidpointRounding 参数
要实现银行舍入,您需要使用标准Math.Round函数中的MidpointRounding.AwayFromZero参数。为了方便起见,我们之前已将此参数添加到我们的自定义Round函数中。根据用户请求,我们还可以设置此参数的默认值,这样您就不必更新所有报告模板。为此,您可以配置以下选项:
StiOptions.Engine.MidpointRounding = MidpointRounding.AwayFromZero;
通过使用上述选项,您可以管理计算准确性并避免将产品迁移到 .NET 时出现的潜在问题。