Math.pow(10, 2) 返回99.99999999999999是因为其底层用exp(b*ln(a))的浮点计算,而ln(10)和exp()存在二进制舍入误差,导致结果略小于100,误差约1e-15量级。

Java 中 Math.pow(double a, double b) 是用底层 C 库(如 IEEE 754 兼容的 pow() 函数)实现的,不是简单循环乘法,而是基于对数和指数运算:exp(b * ln(a))。这导致它对整数幂也走浮点路径,结果可能有精度误差。
为什么 Math.pow(10, 2) 有时返回 99.99999999999999?
根本原因是:所有输入参数都被当作 double 处理,而 double 是二进制浮点数,无法精确表示很多十进制小数(比如 0.1、0.2,甚至某些整数的对数)。例如 Math.pow(10, 2) 实际计算的是 exp(2 * ln(10)),而 ln(10) 和 exp() 都存在舍入误差,最终结果可能略小于 100。
-
Math.pow(5, 3)可能返回124.99999999999999而非125.0 - 误差通常在
1e-15量级,对大多数场景可忽略,但涉及取整、比较或金融计算时会暴露问题
整数幂建议用自定义整数幂函数
当底数和指数都是整数(尤其指数不大),应避免 Math.pow,改用循环乘法或快速幂,保证结果精确:
public static long pow(long base, int exp) {
if (exp == 0) return 1;
if (base == 0) return 0;
if (exp < 0) throw new IllegalArgumentException("负指数不支持");
long result = 1;
long b = base;
int e = exp;
while (e > 0) {
if ((e & 1) == 1) result *= b;
b *= b;
e >>= 1;
}
return result;
}- 适用于
long范围内的整数幂(注意溢出检查可自行添加) - 比
Math.pow更快、更准,且无浮点误差 - 若需支持大数,用
BigInteger.pow(int exponent)
必须用 Math.pow 时如何处理精度问题
如果输入含小数、负数或大指数,只能依赖 Math.pow,此时需主动处理误差:
立即学习“Java免费学习笔记(深入)”;
- 对“本该是整数”的结果,加
Math.round()或带容差的四舍五入:(long) Math.round(Math.pow(x, y)) - 比较是否等于某整数时,不用
==,改用误差范围判断:Math.abs(result - expected) - 需要保留小数位数时,用
BigDecimal二次处理(先转字符串再构造,避免 double 构造器误差):new BigDecimal(String.valueOf(Math.pow(a, b))).setScale(6, RoundingMode.HALF_UP)
特殊值和边界情况要提前检查
Math.pow 对特殊输入有明确定义,但容易引发意外:
-
Math.pow(0, 0)返回1.0(数学上未定义,但 Java 规定为 1) -
Math.pow(0, 负数)返回Infinity或NaN -
Math.pow(负数, 非整数)返回NaN(如Math.pow(-2, 0.5)) - 结果溢出时返回
Infinity,下溢时返回0.0
实际使用前应根据业务逻辑校验输入合法性,必要时抛出明确异常。


















