math类静态方法返回特殊值而非抛异常,需主动检查nan/infinity;取整函数逻辑各异,浮点运算应优先用乘法替代pow;金融计算须用bigdecimal,避免精度误差。

Math 类的静态方法不是万能计算器,它只做确定性计算,不处理 NaN、无穷或边界异常——用错参数类型或忽略返回值范围,结果会静默出错。
为什么 Math.sqrt(-1) 不抛异常而是返回 NaN
Java 的 Math 类设计原则是“不中断执行”,所有方法对非法输入都返回定义好的特殊值而非抛异常。Math.sqrt(-1) 返回 NaN,Math.log(-5) 也返回 NaN,Math.pow(0, -1) 返回 Infinity。这意味着你必须主动检查结果是否为 Double.isNaN() 或 Double.isInfinite(),尤其在金融、物理模拟等对数值合法性敏感的场景。
- 不要直接把
Math.sqrt(x)结果当有效数用,先加if (Double.isNaN(result)) { ... } -
Math.acos(x)和Math.asin(x)要求x在 [-1, 1],超界即得NaN,建议前置校验:if (x 1) throw new IllegalArgumentException(...) -
Math.round()对double返回long,对float返回int,类型不匹配容易引发隐式截断(比如(int) Math.round(2.9f)没问题,但(int) Math.round(1e10)会溢出)
Math.floor()、Math.ceil() 和 Math.round() 的取整逻辑差异
三者行为完全不同:floor 向负无穷取整(≤ 原值的最大整数),ceil 向正无穷取整(≥ 原值的最小整数),round 是四舍五入到最近的整数(.5 向正无穷方向舍入)。注意 round 对负数的处理易被误解:例如 Math.round(-1.5) 是 -1(不是 -2),因为它是 floor(x + 0.5) 的等价实现。
- 需要“向零取整”?别用这仨——改用
(long) x强转,或Math.toIntExact(Math.floor(x))(配合异常捕获) - 处理金额时慎用
Math.round(19.555 * 100) / 100.0,浮点误差可能导致19.555 * 100实际是1955.4999999999998,round后变1955;应改用BigDecimal -
Math.floorDiv(a, b)是 Java 8 新增的安全整数除法(向负无穷取整),比a / b更适合模运算场景,比如分页计算:page = Math.floorDiv(index, size)
性能与精度:什么时候不该用 Math.pow(x, 2)
Math.pow(x, 2) 是通用幂函数,内部走指数对数换算,开销大且有精度损失;而 x * x 是直接乘法,快一个数量级,无额外误差。同理,Math.pow(x, 0.5) 不如 Math.sqrt(x),Math.pow(10, n) 不如 Math.scalb(1, n * 3)(近似)或直接字符串拼接(整数幂)。
- 平方、立方优先写
x * x、x * x * x;编译器不会自动优化pow(x, 2) - 底数为
e时用Math.exp(x),比Math.pow(Math.E, x)更准更快 -
Math.hypot(a, b)计算 √(a²+b²),可避免中间结果溢出(比如a = 1e200),比手动写Math.sqrt(a*a + b*b)安全得多
最常被忽略的是 Math 方法的参数和返回值全是原始类型,没有 null 安全,也没有单位或量纲语义——传进 Double.NaN,它照算不误;传进 1e308 算 sqrt 得 Infinity,也不会提醒你已超出有效范围。真正健壮的数学逻辑,永远始于输入校验,止于结果验证。











