Math类非开箱即用的安全工具:不抛异常、不自动转类型、不隐式处理边界值;Math.Sqrt(-1)返回NaN而非报错;Math.Round默认银行家舍入;分页总页数应使用Math.Ceiling。

Math 类不是“开箱即用”的安全数学工具,它不抛异常、不自动转类型、不隐式处理边界值——直接写 Math.Sqrt(-1) 不会报错,但后续所有基于它的计算都会静默变成 NaN。
Math.Round 默认不是四舍五入,是银行家舍入
写 Math.Round(2.5) 得到 2,不是 bug,是设计:默认采用 MidpointRounding.ToEven(四舍六入五取偶)。这在统计场景里能减少累积偏差,但在业务逻辑里常被误判为“算错了”。
- 要严格四舍五入(0.5 总是进一),必须显式传参:
Math.Round(2.5, MidpointRounding.AwayFromZero) -
decimal和double重载不同,别混用:Math.Round(2.5m, MidpointRounding.AwayFromZero)是合法的,但Math.Round(2.5, MidpointRounding.AwayFromZero)是double版本 - 如果只是想砍掉小数部分(比如取整数 ID),用
Math.Truncate更直白,也比强制(int)x安全——后者在x > int.MaxValue时会溢出
Math.Floor / Math.Ceiling / Math.Truncate 在负数下结果完全不同
这三个方法语义完全不等价,互换使用极易引入逻辑错误。例如分页计算总页数:(total + pageSize - 1) / pageSize 是常见整数技巧,但浮点分页更直观——这时该用哪个?
-
Math.Floor(-4.7)→-5.0(向下找 ≤ x 的最大整数) -
Math.Ceiling(-4.7)→-4.0(向上找 ≥ x 的最小整数) -
Math.Truncate(-4.7)→-4.0(向零截断,等价于去掉小数) - 分页总页数应写:
Math.Ceiling((double)total / pageSize);用Round或Truncate在total % pageSize == 0时可能少算一页
Math.Max / Math.Min 编译报 “The call is ambiguous” 怎么修
这不是语法错误,是重载解析失败。Math.Max(5, 3.14) 中一个是 int、一个是 double,C# 找不到同时接受两者的重载签名。
- 统一类型即可:
Math.Max((double)5, 3.14)或Math.Max(5.0, 3.14) -
short、byte没有专属重载,会先隐式提升为int,再参与比较;真要保精度,建议显式转int或用泛型版System.Math.Max<T>(.NET 6+) - 比较三个数不能写
Math.Max(a, b, c),得嵌套:Math.Max(a, Math.Max(b, c))
Math.Sqrt、Math.Log 等函数返回 NaN 而非抛异常
这是最隐蔽的坑:Math.Sqrt(-1) 返回 double.NaN,不崩、不提示,后续任何运算(加减乘除、比较)只要含 NaN,结果几乎全是 NaN,且 == 判断永远为 false。
- 必须手动检查输入合法性:
if (x - 或检查输出:
double result = Math.Sqrt(x); if (double.IsNaN(result)) { /* handle */ } -
Math.Pow(0, -1)返回double.PositiveInfinity,Math.Pow(-2, 0.5)返回NaN——这些都不是异常场景,而是 IEEE 754 规定的行为 - 别指望
try/catch捕获它们,Math类的设计哲学就是“不抛异常”
真正容易被忽略的,是那些不报错却让结果彻底失效的静默行为:比如忘了检查 NaN 就直接用于数据库插入,或把 Math.Round 当作无脑四舍五入用在价格展示上,结果 9.5 元显示成 9 元。这些不是代码写错了,而是对 Math 类契约的理解偏差。


















