考虑一下下面的C#代码...

double x = Math.Round(72.6d, 2, MidpointRounding.ToZero);
double y = Math.Round(82.6d, 2, MidpointRounding.ToZero);

x变成72.59,y变成82.6.

但是为什么呢?按这IEEE754 convertor来算,两者的小数部分是相同的.那么,为什么他们不给出同样的结果呢?

我可以通过执行以下(double)Math.Round(Convert.ToDecimal(72.6d), 2, MidpointRounding.ToZero)项操作来解决这个问题.但我更感兴趣的是知道为什么它似乎没有像预期的那样起作用的答案.

推荐答案

Microsoft documentation,MidpointRounding.ToZero不进行"中点舍入".微软似乎在这里搞砸了界面:

  • MidpointRounding最初被创建为一个枚举,用于在四舍五入为偶数(ToEven)和四舍五入为最接近零(AwayFromZero)之间进行 Select .
  • 后来在Math.Round的基础上增加了其他舍入方法:向负无穷大舍入(ToNegativeInfinity)、向正无穷大舍入(ToPositiveInfinity)和向零舍入(ToZero).请注意,这些不是朝着这些方向中的一个方向旋转到最近的;它们是朝着这些方向中的一个方向旋转的.例如,ToZero、3.1、3.2、3.5、3.6和3.8都四舍五入为3.
  • Microsoft没有使用新名称(如RoundingMethod)创建新的枚举,而是将这些新值作为成员添加到MidpointRounding中.

结果是,所有五种舍入方法的名称都以MidpointRounding.Name的形式命名,即使其中只有两种方法是与中点相关的舍入到最近的方法.

(我们也看到使用To而不是Toward的术语不敏感.3.4四舍五入为3,接近于零.它不会四舍五入为零.IEEE 754对这些舍入方法使用"Forward".)

再加上this documentation告诉我们Math.Round的运算方式是乘以10n并舍入到一个整数,而不是正确地确定对原始数字进行舍入,我们可以看到发生了什么:

  • 72.6转换为double,生成最接近的表示值72.59999999999999431565811391919851303double5859375.再乘以double,得到7259.9999999999990905052982270717620849609375.在向零的方向上四舍五入为一个整数,得到7259.除以double,如果使用的位数少于17位,则得到的72.590000000000003410605131648480892181396484375,打印为72.59.
  • 82.6转换为double,生成82.59999999999999431565811391919851303double5859375.再乘以double,得出8260.这种情况与前一种情况的不同是由于实数相对于可表示数的位置的偶然性.然后8260除以double,产生82.59999999999999431565811391919851303double5859375,,如果使用的数字少于16位,则打印为82.6.

Csharp相关问答推荐

当打印一行x个项目时,如何打印最后一行项目?

将修剪声明放入LINQ中

C#类主构造函数中的调试参数

MudBlazor—MudDataGrid—默认过滤器定义不允许用户修改基本过滤器

为什么SignalR在每个Blazor服务器应用程序启动时最多启动8个服务器?

不带身份的Blazor服务器.Net 8 Cookie身份验证

System.Net.Http.HttpClient.SendAsync(request)在docker容器内的POST方法30秒后停止

调用Task.Run()与DoSomethingAsync()有什么不同?

C#DateTime.ParseExact不使用特定日期

使用带有参数和曲面的注入失败(&Q;)

按需无缝转码单个HLS数据段

同一组件的多个实例触发相同的事件处理程序

使用CollectionView时在.NET Maui中显示数据时出现问题

如何在一次数据库调用中为ASP.NET核心身份用户加载角色

try 创建一个C#程序,该程序使用自动实现的属性、覆盖ToString()并使用子类

如何在C#.NET桌面应用程序中动态更改焦点工具上的后退 colored颜色

RavenDb:为什么在字符串==空的情况下过滤会过滤得太多?

无法将.Net Framework 4.8.1升级到.Net 7

.NET6最小API:操作.MapGet之后的响应

ASP.NET Core 7空字符串