ToString("F2") 默认采用银行家舍入(四舍六入五成双),如2.555→"2.56"、2.655→"2.66";需传统四舍五入应先用Math.Round(x,2,MidpointRounding.AwayFromZero);金融计算务必使用decimal类型避免浮点误差。

ToString("F2") 会四舍五入,但不是所有场景都适用
直接用 ToString("F2") 是最常见做法,但它默认按“银行家舍入”(四舍六入五成双)处理,比如 2.555.ToString("F2") 得到的是 "2.56",而 2.655.ToString("F2") 却是 "2.66" —— 看似合理,但财务或报表场景常要求严格“四舍五入到偶数以外的规则”,这时它就不够用了。
实操建议:
- 纯展示且接受银行家舍入:用
value.ToString("F2")或$"{value:F2}" - 需要传统四舍五入(如数学考试场景):先调用
Math.Round(value, 2, MidpointRounding.AwayFromZero),再转字符串 - 注意
double本身存在精度误差,0.1 + 0.2不等于0.3,格式化前最好确认原始值是否已按需截断或修正
string.Format 和插值字符串里的 "N2" 与 "F2" 差在哪
"N2" 和 "F2" 都能输出两位小数,但前者带千位分隔符和本地化符号,后者只管小数位。比如在中文系统下,string.Format("{0:N2}", 12345.678) 输出 "12,345.68",而 "{0:F2}" 输出 "12345.68"。
实操建议:
- 做金额展示且需符合当地习惯(如加逗号、货币符号):优先用
"N2"或更明确的"C2"(Currency) - 做日志、API 返回、数据库写入等对格式敏感的场景:用
"F2",避免意外插入分隔符导致解析失败 -
"C2"依赖当前线程的CultureInfo,若服务跨区域部署,建议显式传入CultureInfo.InvariantCulture防止环境差异
Math.Round 的第三个参数容易被忽略
Math.Round(3.45, 1) 默认返回 3.4,不是 3.5 —— 因为它的默认舍入模式是 MidpointRounding.ToEven(即“向偶数舍入”)。很多开发者卡在这儿,以为函数坏了。
实操建议:
- 明确要“远离零”的四舍五入:必须写全三个参数,如
Math.Round(x, 2, MidpointRounding.AwayFromZero) - 不要对
float直接用Math.Round,先转double或decimal,否则浮点误差会放大舍入偏差 - 如果目标是“截断”而非“舍入”(比如只要前两位小数,不进位),别用
Round,改用Math.Truncate(value * 100) / 100
decimal 才是金融计算的正确起点
用 double 做金额计算再格式化,哪怕显示看着对,中间过程可能已经失真。比如 19.99m + 0.01m == 20.00m 永远成立,但 19.99 + 0.01 == 20.00 在 double 下大概率是 false。
实操建议:
- 只要涉及钱、税率、百分比累计等需精确小数运算的场景,变量类型从一开始就用
decimal -
decimal的格式化行为和double一致("F2"、Math.Round等都可用),但底层无二进制表示误差 - 从数据库读取时注意字段类型匹配:SQL Server 的
decimal(18,2)应映射为 C# 的decimal,不是double或float
事情说清了就结束。格式化只是表象,真正决定结果的是你用什么类型存、怎么算、以及要不要让舍入规则透明可控。










