You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#/.NET中Math.Round舍入结果不一致问题咨询

为什么Math.Round(9.995, 2, MidpointRounding.AwayFromZero)返回9.99而非预期的10?

嘿,这个问题其实是二进制浮点数的经典精度陷阱,不是.NET框架的舍入逻辑出问题了!让我给你拆解清楚:

核心原因:double类型存不下精确的9.995

咱们用的double是二进制浮点数,它只能精确表示那些能拆成x除以2的n次方的数。像9.995这种十进制小数,转换成二进制后是无限循环的,根本没法精确存储——内存里实际存的是比9.995略小一丢丢的近似值(具体是9.994999999999998181010596454143524169921875)。

当你调用Math.Round的时候,这个实际值并不是严格的“中点”(也就是刚好在9.99和10.00正中间),而是更靠近9.99。所以按照MidpointRounding.AwayFromZero“远离零舍入”的规则,自然就舍到9.99了。

那为什么9.95能得到10呢?巧了,9.95转成double后,实际存的是比9.95略大一点的近似值(9.9500000000000010658141036401502788066864013671875),这个值超过了中点,所以舍入到1位小数时就向上进成10.0了。

解决方案:用Decimal类型搞定精确十进制舍入

要解决这个问题,直接换用.NET里的decimal类型就行——它是专门为十进制小数设计的,能精确表示像9.995这种数,完全避开二进制浮点数的精度问题。

代码示例:

// 注意加m后缀,告诉编译器这是decimal字面量
var correctResult1 = Decimal.Round(9.995m, 2, MidpointRounding.AwayFromZero);
Console.WriteLine(correctResult1); // 输出 10.00

var correctResult2 = Decimal.Round(9.95m, 1, MidpointRounding.AwayFromZero);
Console.WriteLine(correctResult2); // 输出 10.0

小提醒:

  • 一定要给字面量加m后缀,不然编译器会先把它当成double处理,再转成decimal的时候已经带精度误差了,那还是白搭。
  • decimal精度高但数值范围小,适合货币计算、需要严格精确的小数场景;double更适合科学计算这种不需要十进制精确的场景。

怎么验证浮点数的实际值?

如果你想亲眼看看double存的到底是什么,可以用这段代码打印高精度的数值:

double d = 9.995;
Console.WriteLine(d.ToString("F20"));
// 输出:9.99499999999999818101

这下就能明白为啥舍入结果和你预期的不一样了吧?

内容的提问来源于stack exchange,提问作者biscuitcleaver

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:55:31