math类非万能:不处理异常、不自动类型转换、不隐式适配范围;round默认银行家舍入,非四舍五入;truncate、floor、ceiling负数行为迥异;max/min需统一参数类型;sqrt等函数遇非法输入返回nan而非抛异常。

Math类不是万能工具箱,它不处理异常、不自动类型转换、不隐式适配数值范围——用错一个参数或忽略一个返回值,结果就可能静默偏离预期。
Math.Round 默认不是“四舍五入”
很多人写 Math.Round(2.5) 期望得到 3,结果却是 2。这是因为默认采用银行家舍入(MidpointRounding.ToEven):0.5 总是向偶数方向舍入。这在财务计算中可减少系统性偏差,但日常逻辑里容易误判。
- 要严格向上舍入 0.5,必须显式传参:
Math.Round(2.5, MidpointRounding.AwayFromZero) - 对
decimal类型也适用同样规则,但重载签名不同,别混用double和decimal参数 - 如果只是想截断小数(比如取整数部分),
Math.Truncate比Math.Round更直白,也更安全(不触发舍入逻辑)
Math.Floor、Math.Ceiling、Math.Truncate 在负数下结果完全不同
写分页、索引计算或坐标对齐时,这三个方法常被互换使用,但它们的语义根本不同:
-
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),不是Math.Round或Math.Truncate
Math.Max/Min 编译报错“The call is ambiguous”怎么修
写 Math.Max(5, 3.14) 直接编译失败,不是语法错,而是重载解析失败:C# 找不到同时接受 int 和 double 的 Max 方法。
- 必须统一类型:用
Math.Max((double)5, 3.14)或Math.Max(5.0, 3.14) -
short、byte没有专属重载,会先隐式转成int,再参与比较;若真要比较short值,建议显式转int或用泛型System.Math.Max<t></t>(.NET 6+) - 比较三个数不能写
Math.Max(a, b, c),得嵌套:Math.Max(a, Math.Max(b, c))
Math.Sqrt、Math.Pow 等函数不抛异常,但返回 NaN 或 Infinity
Math.Sqrt(-1) 不会崩,但返回 double.NaN;后续拿这个结果做加减乘除,整个表达式大概率变成 NaN,且不会报错——这种静默失效最难调试。
- 所有输入可能非法的函数(
Sqrt、Log、Acos、Asin)都应前置检查:if (x 或至少用 <code>double.IsNaN(result)验证 -
Math.Pow(0, -1)返回double.PositiveInfinity,不是异常;Math.Pow(-2, 0.5)返回NaN - 不要依赖 try/catch 捕获这些函数的“错误”,它们的设计哲学就是不抛异常
最易被忽略的是:所有 Math 方法都不处理溢出(比如 Math.Abs(int.MinValue) 会返回 int.MinValue,仍是负数),也不校验参数有效性。它只做纯数学映射——你给什么,它算什么,至于对不对,得你自己兜底。










