首页 > 解决方案 > Windows .NET 更新后最后一位数字的四舍五入

问题描述

Windows 更新后,一些计算值在最后一位发生了变化,例如从 -0.0776529085243926 到 -0.0776529085243925。变化总是减少 1 并且偶数和奇数都会受到影响。这似乎与 KB4486153 有关,因为还原此更新会将值更改回以前的值。

在 Visual Studio 中调试并将鼠标悬停在变量上时,已经可以看到此更改。该值稍后会写入输出文件并在其中进行更改(不运行调试器)。

最小的可重现示例

var output = -0.07765290852439255;
Trace.WriteLine(output); // This printout changes with the update.

var dictionary = new Dictionary<int, double>();
dictionary[0] = output; // Hover over dictionary to see the change in debug mode

背景

计算值来自

output[date] = input[date] / input[previousDate] - 1;

不考虑浮点运算中的精度损失,我可以在立即窗口中进行计算,-0.07765290852439255并在升级前后都得到。

但是,当将鼠标悬停在output变量上时,我
{[2011-01-12 00:00:00, -0.0776529085243926]}会在升级之前看到
{[2011-01-12 00:00:00, -0.0776529085243925]}之后,并且这种差异也会传播到输出文件。

更新前后的计算值似乎相同,但其表示的舍入方式不同。

输入值为

{[2011-01-11 00:00:00, 0.983561000400506]} 
{[2011-01-12 00:00:00, 0.907184628008246]}

目标框架设置为.NET Framework 4.6.1

问题

在保持更新的同时,我可以做些什么来获得以前的行为吗?

我知道浮点计算中的精度损失,但是为什么在更新之后会发生这种变化,我们如何保证未来的更新不会改变值的表示?

KB4486153 是 Microsoft .NET Framework 4.8 的更新,请参阅https://support.microsoft.com/en-us/help/4486153/microsoft-net-framework-4-8-on-windows-10-version-1709- windows-10 版本

标签: c#floating-point.net-4.8

解决方案


OP 遇到了浮点数学的常见问题之一。使用新软件,需要一致的答案还是最佳答案?(升级更好)


一些有助于推进问题的信息。

var output = -0.07765290852439255;

使用常见的binary64编码1,由于 binary64 的二进制性质output取值为

-0.077652908524392 54987160666132695041596889495849609375

下面显示了double十六进制和十进制 FP 的前一个和下一个可能。

                      -0.077652908524392 5
-0x1.3e10f9e8d3217p-4 -0.077652908524392 53599381885351249366067349910736083984375
-0x1.3e10f9e8d3218p-4 -0.077652908524392 54987160666132695041596889495849609375
                      -0.077652908524392 55
-0x1.3e10f9e8d3219p-4 -0.077652908524392 56374939446914140717126429080963134765625
                      -0.077652908524392 6

最好的四舍五入到最接近的值-0.077652908524392 55(完全编码为-0.077652908524392 5498...)到少一位数字是 then -0.077652908524392 5。升级后,代码打印出更好的答案——至少在这种特殊情况下是这样。

我不认为这是一个四舍五入的变化,而是一个改进的文本转换。

在保持更新的同时,我可以做些什么来获得以前的行为吗?

也许,但看起来更新提供了更好的结果。

我们如何保证未来的更新不会改变值的表示

使用十六进制浮点输出(如"%a"在 C 中)是一种获得不改变表示的方法,但非十进制输出是不熟悉的。


1使用其他编码,确切值可能更-0.077652908524392 6接近于-0.077652908524392 5


推荐阅读